2015-02-06 72 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不是一個依賴型,所以這被認爲是一種非推導出上下文。編譯器拒絕你的代碼是正確的。