转发初始化列表表达式

时间:2015-02-06 17:04:29

标签: c++ templates c++11 initializer-list

初始化列表表达式非常适合初始化C ++容器:

std::vector<int>({1, 2, 3})

...但似乎括号括起的初始化列表表达式(如{1,2,3}绑定到一个带std::initializer_list<int>的函数 - 它似乎绑定到通用(转发)引用

template <class T>
void foo(T&& v)
{
  std::vector<int>(std::forward<T>(v));
}

int main()
{
  foo({1, 2, 3})
}

输出:

test2.cpp:11:6: note: template<class U> void foo(U&&)
test2.cpp:11:6: note:   template argument deduction/substitution failed:
test2.cpp:33:13: note:   couldn't deduce template parameter ‘U’

(这是GCC 4.7.2的结果。)

遗憾的是,这意味着我们无法转发初始化列表表达式。由于这样做非常方便,我想问为什么这不起作用?为什么括号封闭的初始化列表表达式不能绑定到转发引用?或者这是允许的,也许我的编译器太老了?

2 个答案:

答案 0 :(得分:13)

不是它不能绑定到你的函数的参数;只是编译器无法检测到模板的类型。这编译:

#include <vector>

template <class T>
void foo(T&& v)
{
  std::vector<int>(std::forward<T>(v));
}

int main()
{
  foo(std::initializer_list<int>{1, 2, 3});
}

答案 1 :(得分:4)

在这种情况下无法推断初始化列表。这实际上由[temp.deduct.call]中的标准明确涵盖:

  

模板参数推导是通过比较每个函数模板参数类型(称之为P)来完成的   调用的相应参数的类型(称之为A),如下所述。如果P是依赖类型,   [...]。否则,初始化列表参数会导致参数被视为非推导参数   背景(14.8.2.5)。 [例如:

template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
f({1,"asdf"}); // error: T deduced to both int and const char*

template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T

此处g的示例正是您的情况 - T不是依赖类型,因此这被认为是非推断的上下文。编译器拒绝你的代码是正确的。