int a [] {(functioncall(a1,a2),0)...} (void(a));这个语法是什么意思? [英] int a[] { (functioncall(a1, a2), 0)...}; (void(a)); What does this syntax do/mean?

查看:161
本文介绍了int a [] {(functioncall(a1,a2),0)...} (void(a));这个语法是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我碰到了这篇文章可变模板函数来连接std :: vector容器建议使用以下语法:

 模板< 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;
}



我开始玩弄它以了解它是如何工作的, t看到这个:

  int unpack [] {(append_to_vector(v1,vr),0)...} 
(void(unpack));

似乎这是一种动态生成的初始化列表,我也很困惑的事实,上面的 0 没有关系。我替换了-1和5,这些值每个都很好。



有人可以告诉我这个技术/语法的名称,在上面的两行?我真的很感激任何指针,如果我错过相关的SO职位,道歉。

解决方案

  int unpack [] {(append_to_vector(v1,vr),1)。 ..}; 
// ^^ | | ||| | array of ints
// ^ | | ^数组初始化器
// ^ |逗号运算符
// ^^^包扩展

这是创建一个< c $ c> int s包含与参数包 vr 的大小相同的元素。数组中的每个元素 1 ,这是逗号运算符在计算两个参数后返回。最后一个省略号表示参数包的包扩展 vr 正在完成。



所以如果你要调用你的函数 concat_version3(v1,v2,v3 )其中所有参数向量 s,则上述表达式将导致

  int unpack [] {(append_to_vector(v1,v2),1),(append_to_vector(v1,v3),1)}; 

braced-init-list 中评估表达式的好处是



§8.5.4/ 4 [dcl.init.list] p>


braced-init-list initializer-list > initializer-clause ,包括包展开(14.5.3)的任何结果,按照它们出现的顺序。




因此,您可以确保 v2 附加到 v1 v3 ,这是您想要的。






 (void(unpack)); 

这只是一种避免编译器未使用的变量警告的方法。






现在,我会把你的 unpack 初始化有点不同。

  int unpack [] {1,(append_to_vector(v1,vr),1)...} 
// ^^

在原始代码中,如果调用函数 concat_version3(v1),即使用空参数包,代码将不会编译,因为您将尝试创建一个零大小的数组,添加额外的元素修复这个问题。 / p>

此外,如果你在更通用的代码中使用上面的表达式,你不知道 append_to_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;
}

演示



注意: void cast由于 clang bug 而需要。


I came across this post variadic template function to concatenate std::vector containers suggesting the use of the following syntax:

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;
}

I started playing around with it to understand how it worked, since I haven't seen this:

int unpack[] { (append_to_vector(v1, vr), 0)... };
(void(unpack));

Seems like this is some kind of dynamically generated initialization list that also has side effects? I'm also puzzled by the fact that the 0 above doesn't matter. I substituted, -1 and 5, and each of these values worked just fine too.

So can someone tell me the name of this technique/syntax and what exactly is happening in the two lines above? I'd really appreciate any pointers and apologize if I missed the relevant SO posts.

解决方案

int unpack[] { (append_to_vector(v1, vr), 1)... };
//        ^^ |                          |   ||| |    array of ints
//           ^                          |    |  ^    array initializer
//                                      ^    |       comma operator
//                                          ^^^      pack expansion

This is creating an array of ints containing as many elements as the size of the parameter pack vr. Each element in the array is 1, which is what the comma operator returns after evaluating both arguments. The final ellipsis indicates pack expansion of the parameter pack vr is being done.

So if you were to call your function as concat_version3(v1, v2, v3) where all arguments are vectors, then the above expression would result in

int unpack[]{ (append_to_vector(v1, v2), 1), (append_to_vector(v1, v3), 1) };

The nice thing about evaluating expressions within a braced-init-list is that the order of evaluation is fixed and happens left to right.

§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.

So you're guaranteed that v2 gets appended to v1 before v3, which is what you want.


(void(unpack));

This is just a way to avoid unused variable warnings from the compiler.


Now, I would write your unpack initialization a bit differently.

int unpack[] { 1, (append_to_vector(v1, vr), 1)... };
//             ^^

In the original, if you called the function as concat_version3(v1), i.e. with an empty parameter pack, the code wouldn't compile because you'd be attempting to create a zero sized array, adding the extra element fixes that problem.

Furthermore, if you were using the above expression in more generic code where you didn't know what the return type of append_to_vector was, then you'd also need to guard against the possibility of it returning a type that overloads the comma operator. In that case you'd write

int unpack[] { 1, (append_to_vector(v1, vr), void(), 1)... };

By adding the void() expression in between you ensure that no overloaded comma operator is selected, and the built-in one is always called.


Finally, if you have a compiler that understands fold expressions, you can do away with the whole array trick and simply write

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;
}

Live demo

Note: the extra parentheses after the void cast are required due to a clang bug.

这篇关于int a [] {(functioncall(a1,a2),0)...} (void(a));这个语法是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆