我在看std:variant
/std::visit
在这里DOC:http://en.cppreference.com/w/cpp/utility/variant/visit也是一派很多试图了解背后的神奇std::visit
和std::variant
。
所以我的问题如下。在提供的示例中,在多态lambda和“重载”中,都发生了一些“魔术”,使得可以从中提取正确的类型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
,将其强制转换并将其分派给适当的函数。我的问题是如何运作?同样的交易:
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的变体。找出正确类型的逻辑在哪里,以便using T = std::decay_t<decltype(arg)>;
检索变量特定实例的实际类型?
我的想法是,在后台std::visit
构建一个函数指针数组(在编译时),该数组由每种类型的实例化函数指针组成。该变量存储一个运行时类型索引i
(整数),这使得可以选择i
第-th个函数指针并插入该值。
您可能想知道我们如何在编译时间数组中存储具有不同参数类型的函数指针?->这是通过类型擦除(我认为)完成的,这意味着可以使用例如void*
参数存储函数,例如&A<T>::call
:
template<typename T>
struct A
{
static call(void*p) { otherFunction(static_cast<T*>(p)); }
}
其中每个参数都使用参数call
分派到正确的函数otherFunction
(这是最后的lambda)。类型擦除意味着功能auto f = &A<T>::call
不再具有类型概念T
并且具有签名void(*)(void*)
。
std::variant
由于许多强大的高级元编程技巧开始发挥作用,所以它确实非常复杂且非常复杂。这个答案可能只涵盖冰山一角:-)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句