std :: visit如何与std :: variant一起使用? [英] How does std::visit work with std::variant?

查看:222
本文介绍了std :: visit如何与std :: variant一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查看 std:variant / std :: visit 此处的文档: http://en.cppreference.com/w/cpp/utility/variant/visit 并在Google上进行了大量搜索,试图了解 std :: visit std :: variant 背后的魔力。

I'm looking at std:variant/std::visit doc here: http://en.cppreference.com/w/cpp/utility/variant/visit and also googled a lot trying to understand the magic behind std::visit and std::variant.

所以我的问题如下。在提供的示例中,多态lambda 和重载有一些魔术这样一来,就有可能从 std :: variant 中提取正确的类型。

So my question is the following. In the provided example, both in the polymorphic lambda and the "overloaded" there is some "magic" happening that makes it possible to extract the correct type from std::variant.

因此,请看以下内容:

for (auto& v: vec) {
    std::visit(overloaded {
        [](auto arg) { std::cout << arg << ' '; },
        [](double arg) { std::cout << std::fixed << arg << ' '; },
        [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
    }, v);
}

对于每个 v 一个变体,如何调用正确的重载lambda函数?似乎有些逻辑需要弄清楚特定 std :: variant 所持有的确切类型,将其强制转换并分派给适当的函数。我的问题是如何运作?

For each v, which is just a variant, how does the right overloaded lambda function being invoked? It seems there is some logic that needs to figure out the exact type held by the specific std::variant, cast it and dispatch it to the proper function. My question is how does it work? Same deal for this:

    std::visit([](auto&& arg) {
        using T = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<T, int>)
            std::cout << "int with value " << arg << '\n';
        else if constexpr (std::is_same_v<T, long>)
            std::cout << "long with value " << arg << '\n';
        else if constexpr (std::is_same_v<T, double>)
            std::cout << "double with value " << arg << '\n';
        else if constexpr (std::is_same_v<T, std::string>)
            std::cout << "std::string with value " << std::quoted(arg) << '\n';
        else 
            static_assert(always_false<T>::value, "non-exhaustive visitor!");
    }, w);

我们将多态lambda作为可调用对象传递给访问者,并传递 w 是一些可以容纳int,long,double或std :: string的变体。找出正确类型的逻辑在哪里,因此使用T = std :: decay_t< decltype(arg)> ;; 来检索a的特定实例的实际类型。

We pass polymorphic lambda to the visitor as the callable object and w is some variant that can hold int, long, double or std::string. Where is the logic that figures out the right type so using T = std::decay_t<decltype(arg)>; to retrieve the actual type of the specific instance of a variant?

推荐答案

我认为是 std :: visit 构建一个函数指针数组(在编译时),该数组由每种类型的实例化函数指针组成。该变体存储运行时类型索引 i (整数),这使得可以选择正确的 i -函数指针并注入值。

What I think, is that under the hood std::visit builds an array of function pointers (at compile time) which consists of instantiated function pointers for each type. The variant stores a run-time type index i (intgeral number) which makes it possible to select the right i-th function pointer and inject the value.

您可能想知道我们如何在编译时间数组中存储具有不同参数类型的函数指针? ->这是通过类型擦除来完成的(我认为),这意味着
可以存储例如 void * 参数,例如& A&T; :: call

You might wonder how can we store function pointers with different argument types in a compile time array? -> This is done with type-erasure (I think), which means one stores functions with e.g. a void* argument, e.g. &A<T>::call:

template<typename T>
struct A
{
   static call(void*p) { otherFunction(static_cast<T*>(p)); } 
}

其中每个呼叫都派发给正确的函数 otherFunction 带有参数(这是最后的lambda)。
类型擦除表示函数 auto f =& A< T> :: call 没有类型 T 并具有签名 void(*)(void *)

where each call dispatches to the correct function otherFunction with the argument (this is your lambda at the end). Type erasure means the function auto f = &A<T>::call has no more notion of the type T and has signature void(*)(void*).

std ::变体确实很复杂而且非常复杂,因为许多强大的花哨的元编程技巧都在发挥作用。这个答案可能只涵盖冰山一角:-)

std::variant is really complicated and quite sophisticated as lots of powerful fancy metaprogramming tricks come into play. This answer might only cover the tip of the iceberg :-)

这篇关于std :: visit如何与std :: variant一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆