【问题标题】:Why does std::visit take a variable number of variants?为什么 std::visit 采用可变数量的变体?
【发布时间】:2017-10-04 08:04:47
【问题描述】:

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

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

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

那么,为什么要进行这种特定的“变体”?

【问题讨论】:

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


    【解决方案1】:

    使多次访问更清洁。假设我有两个std::variant&lt;A,B&gt;,一个名为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);
    

    这写起来很糟糕,读起来很糟糕,而且效率也可能更低。

    【讨论】:

    • 所以,我通过阅读您的答案找出了需要std::visit 的原因,但您有点假设我已经知道答案。请参阅下面我建议的答案...
    • @einpoklum 您从阅读我的答案中找到了答案,但我的回答并没有帮助您找到答案?
    • 确实如此(这就是我 +1 你的原因),但它只是帮助我找出答案,而不是 答案。
    【解决方案2】:

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

    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) - 当查看一对 Var1 和 @987654334 时@一起。这就是为什么 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时发现了这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-24
      • 1970-01-01
      • 2022-06-10
      • 2019-06-19
      • 1970-01-01
      • 2016-07-31
      • 1970-01-01
      相关资源
      最近更新 更多