2015-02-06 69 views
10

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

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

+1

转发'initializer_list'没有用:它已经有引用语义,其元素是const的,因此不可移动。 – dyp 2015-02-06 17:07:10

+0

无关紧要,它们是否可移动 - 通用转发参考不一定意味着移动,它只是意味着沿参数转发,因为 – Siler 2015-02-06 17:08:12

+3

是的,但是braced-init-list没有类型。因此,你不能“原样”转发它。 – dyp 2015-02-06 17:09:05

回答

10

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

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

在这种情况下,不能推导出初始值列表。这实际上是由[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不是一个依赖型,所以这被认为是一种非推导出上下文。编译器拒绝你的代码是正确的。