int a[] { (functioncall(a1, a2), 0)...}; (无效(一));这个语法 do/mean 是什么意思?
int a[] { (functioncall(a1, a2), 0)...}; (void(a)); What does this syntax do/mean?
我遇到了这个 post variadic template function to concatenate std::vector containers 建议使用以下语法:
template<typename T>
void append_to_vector(std::vector<T>& v1, const std::vector<T>& v2) {
std::cout << v2[0] << std::endl;
for (auto& e : v2) v1.push_back(e);
}
template<typename T, typename... A>
std::vector<T> concat_version3(std::vector<T> v1, const A&... vr) {
int unpack[] { (append_to_vector(v1, vr), 1)... };
(void(unpack));
return v1;
}
我开始尝试它以了解它是如何工作的,因为我还没有看到这个:
int unpack[] { (append_to_vector(v1, vr), 0)... };
(void(unpack));
好像这是某种动态生成的初始化列表,也有副作用?我也对上面的 0
无关紧要这一事实感到困惑。我替换为 -1 和 5,这些值中的每一个都工作得很好。
所以有人可以告诉我这个 technique/syntax 的名称以及上面两行中到底发生了什么吗?如果我错过了相关的 SO post,我将非常感谢任何指点并道歉。
int unpack[] { (append_to_vector(v1, vr), 1)... };
// ^^ | | ||| | array of ints
// ^ | | ^ array initializer
// ^ | comma operator
// ^^^ pack expansion
这将创建一个 int
数组,其中包含与参数包 vr
大小一样多的元素。数组中的每个元素都是1
,也就是参数包vr
的comma operator returns after evaluating both arguments. The final ellipsis indicates pack expansion正在做的
因此,如果您将函数调用为 concat_version3(v1, v2, v3)
,其中所有参数均为 vector
,则上述表达式将导致
int unpack[]{ (append_to_vector(v1, v2), 1), (append_to_vector(v1, v3), 1) };
在 braced-init-list 中计算表达式的好处是计算顺序是固定的,从左到右发生。
§8.5.4/4 [dcl.init.list]
Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear.
所以你保证 v2
在 v3
之前附加到 v1
,这就是你想要的。
(void(unpack));
这只是避免编译器发出未使用变量警告的一种方法。
现在,我会以不同的方式编写您的 unpack
初始化。
int unpack[] { 1, (append_to_vector(v1, vr), 1)... };
// ^^
在最初,如果您将函数调用为 concat_version3(v1)
,即使用空参数包,代码将无法编译,因为您将尝试创建一个零大小的数组,添加额外的element 解决了这个问题。
此外,如果您在不知道 append_to_vector
的 return 类型是什么的更通用代码中使用上述表达式,那么您还需要防范它 return 重载逗号运算符的类型的可能性。在那种情况下你会写
int unpack[] { 1, (append_to_vector(v1, vr), void(), 1)... };
通过在中间添加 void()
表达式,确保不会选择重载的逗号运算符,并且始终调用内置的逗号运算符。
最后,如果你有一个理解 fold expressions 的编译器,你可以取消整个数组技巧并简单地写
template<typename T, typename... A>
std::vector<T> concat_version3(std::vector<T> v1, const A&... vr)
{
(void)(((append_to_vector(v1, vr), void()), ...));
return v1;
}
注意:由于 .
,void
强制转换后需要额外的括号
我遇到了这个 post variadic template function to concatenate std::vector containers 建议使用以下语法:
template<typename T>
void append_to_vector(std::vector<T>& v1, const std::vector<T>& v2) {
std::cout << v2[0] << std::endl;
for (auto& e : v2) v1.push_back(e);
}
template<typename T, typename... A>
std::vector<T> concat_version3(std::vector<T> v1, const A&... vr) {
int unpack[] { (append_to_vector(v1, vr), 1)... };
(void(unpack));
return v1;
}
我开始尝试它以了解它是如何工作的,因为我还没有看到这个:
int unpack[] { (append_to_vector(v1, vr), 0)... };
(void(unpack));
好像这是某种动态生成的初始化列表,也有副作用?我也对上面的 0
无关紧要这一事实感到困惑。我替换为 -1 和 5,这些值中的每一个都工作得很好。
所以有人可以告诉我这个 technique/syntax 的名称以及上面两行中到底发生了什么吗?如果我错过了相关的 SO post,我将非常感谢任何指点并道歉。
int unpack[] { (append_to_vector(v1, vr), 1)... };
// ^^ | | ||| | array of ints
// ^ | | ^ array initializer
// ^ | comma operator
// ^^^ pack expansion
这将创建一个 int
数组,其中包含与参数包 vr
大小一样多的元素。数组中的每个元素都是1
,也就是参数包vr
的comma operator returns after evaluating both arguments. The final ellipsis indicates pack expansion正在做的
因此,如果您将函数调用为 concat_version3(v1, v2, v3)
,其中所有参数均为 vector
,则上述表达式将导致
int unpack[]{ (append_to_vector(v1, v2), 1), (append_to_vector(v1, v3), 1) };
在 braced-init-list 中计算表达式的好处是计算顺序是固定的,从左到右发生。
§8.5.4/4 [dcl.init.list]
Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear.
所以你保证 v2
在 v3
之前附加到 v1
,这就是你想要的。
(void(unpack));
这只是避免编译器发出未使用变量警告的一种方法。
现在,我会以不同的方式编写您的 unpack
初始化。
int unpack[] { 1, (append_to_vector(v1, vr), 1)... };
// ^^
在最初,如果您将函数调用为 concat_version3(v1)
,即使用空参数包,代码将无法编译,因为您将尝试创建一个零大小的数组,添加额外的element 解决了这个问题。
此外,如果您在不知道 append_to_vector
的 return 类型是什么的更通用代码中使用上述表达式,那么您还需要防范它 return 重载逗号运算符的类型的可能性。在那种情况下你会写
int unpack[] { 1, (append_to_vector(v1, vr), void(), 1)... };
通过在中间添加 void()
表达式,确保不会选择重载的逗号运算符,并且始终调用内置的逗号运算符。
最后,如果你有一个理解 fold expressions 的编译器,你可以取消整个数组技巧并简单地写
template<typename T, typename... A>
std::vector<T> concat_version3(std::vector<T> v1, const A&... vr)
{
(void)(((append_to_vector(v1, vr), void()), ...));
return v1;
}
注意:由于
void
强制转换后需要额外的括号