std :: visit如何使用std :: variant?

Kob*_*obi 10 c++ c++17

我期待在std:variant/std::visit这里DOC:http://en.cppreference.com/w/cpp/utility/variant/visit也是一派很多试图了解背后的神奇std::visitstd::variant.

所以我的问题如下.在所提供的示例中,在多态lambda和"overloaded"中都存在一些"魔术"发生,这使得从中提取正确的类型成为可能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);
}
Run Code Online (Sandbox Code Playgroud)

对于每个v,这只是一个变体,如何调用正确的重载lambda函数?似乎有一些逻辑需要弄清楚具体所持有的确切类型std::variant,将其投射并将其分配给适当的函数.我的问题是它是如何工作的?同样的交易:

    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);
Run Code Online (Sandbox Code Playgroud)

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

Gab*_*iel 5

我的想法是,在后台std::visit构建一个函数指针数组(在编译时),该数组由每种类型的实例化函数指针组成。该变量存储一个运行时类型索引i(整数),这使得可以选择i第-th个函数指针并插入该值。

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

template<typename T>
static A
{
   static call(void*p) { otherFunction(static_cast<T*>(p)); } 
}
Run Code Online (Sandbox Code Playgroud)

其中每个参数都使用参数call分派到正确的函数otherFunction(这是最后的lambda)。类型擦除意味着功能auto f = &A<T>::call不再具有类型概念T并且具有签名void(*)(void*)

std::variant由于许多强大的高级元编程技巧开始发挥作用,所以它确实非常复杂且非常复杂。这个答案可能只涵盖冰山一角:-)