为什么 std::visit 采用可变数量的变体?
Why does std::visit take a variable number of variants?
为了更熟悉 C++17,我刚刚注意到 std::visit
:
template <class Visitor, class... Variants>
constexpr /*something*/ visit(Visitor&& vis, Variants&&... vars);
为什么 std::visit
不采用单个变体,而是采用任意数量的变体?我的意思是,你总是可以采用一些标准库函数,并让它采用具有相同角色的多个参数,处理所有这些参数(例如 std::find()
用于容器中的多个元素);或者您可以吸引多个访问者并在同一个变体上使用它们。
那么,为什么这个特定的 'variadification'?
使多次访问更清洁。假设我有两个 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);
这写起来很痛苦,读起来很痛苦,而且效率可能也很低。
因为我们需要允许在变体中访问 类 的组合。也就是说,如果我们有
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);
};
分别为Var1
和Var2
。我们甚至可以使用下一种,分别使用 Var1
和 Var2
:
struct Visitor3 {
void operator()(A);
void operator()(B);
void operator()(C);
void operator()(D);
};
但是 OP 缺少的是我们希望能够访问四对中的一对 (A,C)
、(A,D)
、(B,C)
、(B,D)
- 在查看时在一对 Var1
和 Var2
一起 。这就是为什么 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);
我在阅读 时发现了这一点。
为了更熟悉 C++17,我刚刚注意到 std::visit
:
template <class Visitor, class... Variants>
constexpr /*something*/ visit(Visitor&& vis, Variants&&... vars);
为什么 std::visit
不采用单个变体,而是采用任意数量的变体?我的意思是,你总是可以采用一些标准库函数,并让它采用具有相同角色的多个参数,处理所有这些参数(例如 std::find()
用于容器中的多个元素);或者您可以吸引多个访问者并在同一个变体上使用它们。
那么,为什么这个特定的 'variadification'?
使多次访问更清洁。假设我有两个 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);
这写起来很痛苦,读起来很痛苦,而且效率可能也很低。
因为我们需要允许在变体中访问 类 的组合。也就是说,如果我们有
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);
};
分别为Var1
和Var2
。我们甚至可以使用下一种,分别使用 Var1
和 Var2
:
struct Visitor3 {
void operator()(A);
void operator()(B);
void operator()(C);
void operator()(D);
};
但是 OP 缺少的是我们希望能够访问四对中的一对 (A,C)
、(A,D)
、(B,C)
、(B,D)
- 在查看时在一对 Var1
和 Var2
一起 。这就是为什么 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);
我在阅读