可变参数模板参数转发使用逗号运算符
Variadic template argument forwarding uses comma operator
最近我正在学习C++和可变参数模板。我尝试编写一个模板函数,该函数采用容器(我简化了它,并且我只使用list
这个问题(和其他一些参数,并将其他参数置换到容器中。我的代码看起来像这样:
#include <iostream>
#include <list>
#include <utility>
template <typename Container, typename... Args>
void my_emplace(Container &c, Args &&... args){
c.emplace_back(std::forward<Args>(args)...);
}
int main(void) {
std::list<int> l = {1, 2};
my_emplace(l, 3, 4, 5);
for (auto i : l)
std::cout << i << ", ";
return 0;
}
但是,代码不起作用:
$ g++ -std=c++17 test.cpp
...
/usr/include/c++/7/ext/new_allocator.h:136:4: error: new initializer expression list treated as compound expression [-fpermissive]
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
我在互联网上找到了一个解决方案——c.emplace_back(std::forward<Args>(args)...);
行被(c.emplace_back(std::forward<Args>(args)), ...);
取代。代码可以很好地工作。
这是我不明白的部分。我从未见过这种语法。
- 为什么我的代码不起作用?这里的这个答案基本上说它是正确的。
- 我找到的正确解决方案实际上有什么作用?我从未使用过逗号运算符,但我发现在使用时,两个表达式都会被计算,第一个表达式的结果会被丢弃。它在这里做什么,为什么没有它代码就不起作用?
谢谢你的回答。
假设参数是(1, 2, 3, 4(,这个调用:
c.emplace_back(std::forward<Args>(args)...);
基本上意味着:
c.emplace_back(1, 2, 3, 4);
,所以你不能用这些参数构造int来emplace_back
因此编译错误。
而这个电话:
(c.emplace_back(std::forward<Args>(args)), ...);
方法
c.emplace_back(1), c.emplace_back(2), c.emplace_back(3), c.emplace_back(4);
第二次调用使用逗号运算符扩展整个表达式,它的调用Fold Expressions
它在 C++17 中添加的 您可以阅读更多关于它的信息 折叠表达式
emplace_back
会将其参数转发给value_type的构造函数,在本例中为int
.这意味着您可以调用c.emplace_back(3)
,但不能调用c.emplace_back(3,4,5)
。
传递多个值时,需要多次调用emplace_back
。
c.emplace_back(3), c.emplace_back(4), c.emplace_back(5);
我们可以在一行上执行此操作,使用上面的逗号运算符。
展开参数包的两种不同方式的工作方式相同。
c.emplace_back(std::forward<Args>(args)...);
// normal un-packing, translates to
c.emplace_back(3, 4, 5);
(c.emplace_back(std::forward<Args>(args)), ...);
// un-packing with a fold-expression using the comma operator
(c.emplace_back(3), c.emplace_back(4), c.emplace_back(5));
从 C++17 开始,您可以使用折叠表达式(参见 super's 和 Gaurav Dhiman 的答案(。
在 C++17(C++11 和 C++14(之前,您可以获得类似的东西 扩展表达式初始化未使用的数组
我的意思是
template <typename Container, typename... Args>
void my_emplace (Container &c, Args && ... args)
{
using unused = int[];
(void)unused { 0, ((void)c.emplace_back(std::forward<Args>(args)), 0)... };
}
观察使用逗号运算符丢弃扩展表达式。
还要观察c.emplace_back()
面前的(void)
。在这种情况下(c
是一个std::list
(是多余的,但添加它以避免返回对象重新定义逗号运算符的潜在问题。
- 如何使基类的运算符对基类的可变参数数可见(请参阅下面的代码)?
- 具有两个间接寻址运算符 (C++) 的函数参数的用途
- 运算符重载:"operator+"必须采用零个或一个参数
- 为什么数组大小信息可用于"sizeof"运算符和 delete[] 运算符,但在将数组作为参数传递到
- 参数相关查找和流运算符重载
- C++:使用运算符 = 调用多参数构造函数
- 了解布尔运算符==(参数 1,参数 2)
- 我能否根据其运算符()的签名专门化可变参数模板参数
- SFINAE 检查模板参数运算符
- 不允许运算符 const 参数调用 const 成员函数
- 为私有结构定义双参数运算符重载
- C++ 通过自定义赋值运算符隐式转换函数参数
- 函数参数变量总是需要 & 或 * 运算符吗?
- 有条件地将默认参数传递给函数(使用"?"运算符)
- 可变参数模板参数转发使用逗号运算符
- C++函数,它将数组、谓词和运算符作为参数,并将运算符应用于满足谓词的数组元素
- 具有两个或多个模板参数的 C++ assigment 运算符
- 将多个参数传递给运算符 []
- 如何使用类的参数重载运算符+?
- 不允许在C++中使用多参数运算符 [] 的根本原因