C++ INTA[]{(函数调用(a1,a2),0)…};(a)项无效;这个语法是什么意思?
我看到这篇文章建议使用以下语法:C++ INTA[]{(函数调用(a1,a2),0)…};(a)项无效;这个语法是什么意思?,c++,templates,c++11,variadic-templates,list-initialization,C++,Templates,C++11,Variadic Templates,List Initialization,我看到这篇文章建议使用以下语法: 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,
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;
}
这似乎是某种动态生成的初始化列表,它也有副作用?我还感到困惑的是,上面的0
并不重要。我替换了-1和5,这两个值也都很好
有人能告诉我这种技术/语法的名称,以及上面两行中到底发生了什么?如果我错过了相关的SO帖子,我将非常感谢您的指点,并向您道歉
int unpack[] { (append_to_vector(v1, vr), 1)... };
// ^^ | | ||| | array of ints
// ^ | | ^ array initializer
// ^ | comma operator
// ^^^ pack expansion
这将创建一个int
s数组,其中包含与参数包vr
大小相同的元素。数组中的每个元素都是1
,这是计算两个参数后返回的值。最后一个省略号表示正在执行参数包vr
因此,如果将函数调用为concat_version3(v1、v2、v3)
,其中所有参数都是vector
s,那么上述表达式将导致
int unpack[]{ (append_to_vector(v1, v2), 1), (append_to_vector(v1, v3), 1) };
在带括号的init列表中计算表达式的好处是,计算顺序是固定的,从左到右
§8.5.4/4【dcl初始清单】
在带括号的init列表的初始值设定项列表中,初始值设定项子句,包括由包扩展(14.5.3)产生的任何子句,按照它们出现的顺序进行计算
因此,您可以保证在v3
之前将v2
附加到v1
,这就是您想要的
这只是避免编译器发出未使用的变量警告的一种方法
现在,我将以稍微不同的方式编写
解包初始化
int unpack[] { 1, (append_to_vector(v1, vr), 1)... };
// ^^
在原始版本中,如果将函数调用为concat_version3(v1)
,即使用空参数包,代码将无法编译,因为您将尝试创建一个零大小的数组,添加额外的元素可以修复该问题
此外,如果您在更一般的代码中使用上述表达式,而您不知道append\u to\u vector
的返回类型是什么,那么您还需要防止它返回的类型可能会重载逗号运算符。那样的话,你会写信的
int unpack[] { 1, (append_to_vector(v1, vr), void(), 1)... };
通过在中间添加void()
表达式,可以确保未选择重载的逗号运算符,并且始终调用内置的逗号运算符
最后,如果您有一个能够理解的编译器,那么您可以取消整个数组技巧,只需编写
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;
}
模板
std::vector concat_version3(std::vector v1,常量A和…vr)
{
(void)((将_附加到_向量(v1,vr),void(),…);
返回v1;
}
注意:void
cast后的额外括号是由于a而需要的。此技术实现了为给定的每个变量参数调用函数append\u to_vector(v1,X)
一次,并依次用每个元素替换X
。我称之为“虚拟数组逗号运算符黑客”,不知道它是否有正式名称:)非常感谢您提供了这个非常全面的答案。非常感谢。折叠表达式案例可以使用<代码>空格 CAST(以防止重载逗号)。谢谢你,没有考虑这个可能性,不知怎么说,折叠表达式看起来太酷了,不易受到这样的陷阱的影响:现在已经固定了。在另一个帖子里,有人问我为什么不支持这个:<代码> AppDeNotoToV矢(V1,VR)。...;代码>具有相同的效果并丢弃返回值,并且我没有answer@M.M我的猜测是,允许省略号应用于扩展的参数包以外的其他对象,而不使用中间运算符,将导致语法歧义。出于类似的原因,我一直认为折叠表达式需要在其周围加括号。
int unpack[] { 1, (append_to_vector(v1, vr), void(), 1)... };
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;
}