简体   繁体   English

int a [] {(functioncall(a1,a2),0)…}; (无效的(a)); 这个语法有什么用?

[英]int a[] { (functioncall(a1, a2), 0)…}; (void(a)); What does this syntax do/mean?

I came across this post variadic template function to concatenate std::vector containers suggesting the use of the following syntax: 我遇到了这个后可变参数模板函数来连接std :: vector容器,建议使用以下语法:

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. 上面的0无关紧要的事实也令我感到困惑。 I substituted, -1 and 5, and each of these values worked just fine too. 我分别用-1和5代替,每个值也都很好。

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. 如果我错过了相关的SO帖子,我将非常感谢任何指导,并深表歉意。

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

This is creating an array of int s containing as many elements as the size of the parameter pack vr . 这将创建一个int数组,其中包含与参数pack vr大小一样多的元素。 Each element in the array is 1 , which is what the comma operator returns after evaluating both arguments. 数组中的每个元素均为1 ,这是逗号运算符在对两个参数求值后返回的结果。 The final ellipsis indicates pack expansion of the parameter pack vr is being done. 最后的省略号表示参数pack vr数据包扩展已完成。

So if you were to call your function as concat_version3(v1, v2, v3) where all arguments are vector s, then the above expression would result in 因此,如果您将函数调用为concat_version3(v1, v2, v3) ,其中所有参数均为vector ,则上述表达式将导致

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] §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 . 内的支撑-INIT-列表初始化列表 ,从包扩展(14.5.3)产生的初始化子句 ,包括任何被以它们出现的顺序进行评价

So you're guaranteed that v2 gets appended to v1 before v3 , which is what you want. 因此,您可以确保将v2附加到v3之前的v1 ,这就是您想要的。


(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. 现在,我将对您的unpack初始化进行一些不同的编写。

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

In the original, if you called the function as concat_version3(v1) , ie 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. 在原始版本中,如果将函数称为concat_version3(v1) ,即使用空参数包,则代码将无法编译,因为您将尝试创建大小为零的数组,添加额外的元素可解决该问题。

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. 此外,如果您在更通用的代码中使用上面的表达式,而您不知道append_to_vector的返回类型是append_to_vector ,那么您还需要避免它返回一个重载逗号运算符的类型的可能性。 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. 通过在两者之间添加void()表达式,可以确保没有选择重载的逗号运算符,并且始终调用内置的运算符。


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 . 注意:由于clang bug ,在void强制转换之后需要额外的括号。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM