转发初始化列表表达式

Forwarding initializer list expressions

初始化列表表达式对于初始化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 的结果。)

不幸的是,这意味着我们无法转发初始化列表表达式。既然这样做会很方便,我想问一下为什么这不起作用?为什么大括号括起来的初始化列表表达式不能绑定到转发引用?或者这是允许的,也许我的编译器太旧了?

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

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

在这种情况下无法推导出初始化列表。 [temp.deduct.call]:

中的标准实际上明确涵盖了这一点

Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below. If P is a dependent type, [...]. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context (14.8.2.5). [ Example:

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 不是依赖类型,因此这被认为是非推导上下文。编译器拒绝你的代码是正确的。