更好地理解std::visit

6

来自https://en.cppreference.com/w/cpp/utility/variant/visit

  1. visit的返回值是什么?我不明白“selected invocation of visitor”是什么意思?

示例代码:

// Don't understand what this means, can explain? It's a templated func with trailing return type but no body?
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

// Why would the visitor function use && instead of &?
std::visit([](auto&& arg){std::cout << arg;}, v);

1
将此代码放入 https://cppinsights.io/ 中,这将展开可变模板,并立即看到正在发生的事情。 请注意,template<class... Ts> overloaded(Ts...) -> overloaded<Ts...> 是一个推导指南。 - Patrick Fromberg
2个回答

7
最简单的理解访客的方式就是将其与多态性进行比较。在多态类中,你有一个基类,其中包含虚函数和派生类,这些派生类覆盖了这些函数。你创建派生类的对象,并将它们存储为基类的对象(大多数情况下是指针)。当你调用基类指针中的虚函数时,它们将调用最初创建的类型的函数,这是派生类类型。
访客完全相同,但是是类型安全的。但是,访客没有基本类型。你基本上将所有“派生”类型,即具有要调用的方法的类型,存储在变量对象中(它们实际上并没有被存储,它们实际上是互斥的,这与variant的性质相关)。variant对其所持有的对象类型是不可知的,就像基类对其持有的派生类型也是不可知的。就像在基类指针中调用方法(如上所述)将导致调用派生中的重写方法一样,在变体中也适用。当你“访问”时,将使用正确的变量类型来调用底层函数。
这里有个问题:当你将多种类型放入变量中并访问它们的方法时,与多态类型结构不同的是,方法不必共享相同的返回类型。因此,如果一个类中的方法返回int,而另一个类中相同名称的另一个方法返回double,并且你访问包含这两个方法的变量,根据实例化在变量中的对象,将返回正确的返回类型。
我知道这段文字太长了,希望对你有所帮助。

2
根据文档std::visit返回的是访问者所返回的值。

被访问者函数选定的返回值。

当使用一个返回void类型的访问者,例如[](auto&& arg){std::cout << arg;}时,std::visit返回的是void类型。
std::visit([](auto&& arg){std::cout << arg;}, v);

使用返回var_t的访问器,例如[](auto&& arg) -> var_t {return arg + arg;}std::visit将返回var_t

var_t w = std::visit([](auto&& arg) -> var_t {return arg + arg;}, v);

overloaded 的作用是创建一个访问者包装:

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

然后,您可以使用以下代码创建访问者:

auto visitor = overloaded {
        [](auto arg) { std::cout << arg << ' '; },
        [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
    };

接下来可以这样调用:

std::visit(visitor, v);

在这种情况下,访问者返回 void ,那么 std::visit 也返回 void

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接