为什么std :: visit采用可变数量的变体?

时间:2017-05-05 18:37:27

标签: c++ std variadic-templates c++17 variant

为了更熟悉C ++ 17,我刚刚注意到std::visit

template <class Visitor, class... Variants>
constexpr /*something*/ visit(Visitor&& vis, Variants&&... vars);

为什么std::visit不采用单个变体,而是采用任意数量的变体?我的意思是,你总是可以采用一些标准的库函数,让它采用具有相同角色的多个参数,处理所有这些参数(例如std::find()用于容器中的多个元素);或者你可以带多个访问者并在同一个变体上使用它们。

那么,为什么这个具体的变化&#39;?

2 个答案:

答案 0 :(得分:25)

使多个访问更清洁。我们假设我有两个std::variant<A,B>,一个名为left,一个名为right。通过多次访问,我可以写:

struct Visitor {
    void operator()(A, A);
    void operator()(A, B);
    void operator()(B, A);
    void operator()(B, B);
};

std::visit(Visitor{}, left, right);

这是一个非常干净的界面,并且非常有用。它也很容易有效地实现 - 您只需创建一个 n 维度函数数组而不是一维数组。

另一方面,只有一次访问,你必须写:

std::visit([&](auto l_elem){
    std::visit([&](auto r_elem){
        Visitor{}(l_elem, r_elem);
    }, right)
}, left);

写作悲惨,阅读悲惨,效率也可能低下。

答案 1 :(得分:3)

因为我们需要允许访问变体中的类的组合。也就是说,如果我们有

using Var1 = std::variant<A,B>;
using Var2 = std::variant<C,D>;

我们显然可以使用这些类型的访问者:

struct Visitor1 {
    void operator()(A);
    void operator()(B);
};

struct Visitor2 {
    void operator()(C);
    void operator()(D);
};

分别为Var1Var2。我们甚至可以单独使用Var1Var2来使用下一种类型:

struct Visitor3 {
    void operator()(A);
    void operator()(B);
    void operator()(C);
    void operator()(D);
};

但缺少OP的是我们希望能够访问四对(A,C)(A,D)(B,C)(B,D)中的一对 - 一对Var1Var2 一起。这就是为什么std::visit的可变参数是全部但必要的原因。适当的访客看起来像这样:

struct Visitor4 {
    void operator()(A,C);
    void operator()(A,D);
    void operator()(B,C);
    void operator()(B,D);
};

我们会致电std::visit(Visitor4{}, my_var1_instance, my_var2_instance);

我在阅读Barry's answer时想到了这一点。