2013-08-01 38 views
4

gcc 4.8.1 &鏗鏘3.3,C++ 11功能齊全, 我需要在某些函數中轉發args,構造像make_shared/C++ 14 make_unique這樣的元素。但我有問題類型推演/轉發初始化列表/陣列完美轉發,可變參數模板,initializer_list - 一起

我需要工作的foo * foo3{ make_it<foo>({{1,1},{ 10,10 }}, 10) };例子,所以std::initializer_list會演繹出它的參數和功能將它們轉發

#include <initializer_list> 
#include <algorithm> 

struct foo 
    { 
    struct pairs{ int a,b; }; 

    foo(int value){} 
    foo(std::initializer_list<pairs> elems, int value){} 
    }; 

//some custom allocation mechanizm 
char store[sizeof(foo)*2]; 
char * store_ptr = &store[0]; 
void * allocfromstore(size_t sz) { void * ret = store_ptr; store_ptr+= sz; return ret; } 


template<typename ValueType, typename ArrType, typename... Args> 
ValueType * make_it(std::initializer_list<ArrType> il, Args&&... args) 
{ 
    ValueType * obj = new (allocfromstore(sizeof(ValueType))) ValueType(il, std::forward<Args>(args)...); 
    return obj; 
} 


template<typename ValueType, typename... Args> 
ValueType * make_it(Args&&... args) 
{ 
    ValueType * obj = new (allocfromstore(sizeof(ValueType))) ValueType(std::forward<Args>(args)...); 
    return obj; 
} 
std::initializer_list<foo::pairs> encapsulate(std::initializer_list<foo::pairs> il){ return il; } 
int main(){ 

    foo * foo0{ make_it<foo>(10) }; 
    foo * foo1{ make_it<foo>(std::initializer_list<foo::pairs>({{1,1},{ 10,10 }}), 10) }; 
    foo * foo2{ make_it<foo>(encapsulate({{1,1},{ 10,10 }}), 10) }; 
    foo * foo3{ make_it<foo>({{1,1},{ 10,10 }}, 10) }; 
return 0; 
} 

實際上foo3將失敗,鐺3.3:

test.cpp:37:15: error: no matching function for call to 'make_it' 
    foo * foo3{ make_it<foo>({{1,1},{ 10,10 }}, 10) }; 
       ^~~~~~~~~~~~ 
test.cpp:18:13: note: candidate template ignored: couldn't infer template argument 'ArrType' 
ValueType * make_it(std::initializer_list<ArrType> il, Args&&... args) 
      ^
test.cpp:26:13: note: candidate function not viable: requires 0 arguments, but 2 were  provided 
ValueType * make_it(Args&&... args) 
      ^
1 error generated. 

,並用gcc 4.8.1:

test.cpp: In function ‘int main()’: 
test.cpp:37:51: error: no matching function for call to ‘make_it(<brace-enclosed initializer list>, int)’ 
    foo * foo3{ make_it<foo>({{1,1},{ 10,10 }}, 10) }; 
               ^
test.cpp:37:51: note: candidates are: 
test.cpp:18:13: note: template<class ValueType, class ArrType, class ... Args> ValueType* make_it(std::initializer_list<ArrType>, Args&& ...) 
ValueType * make_it(std::initializer_list<ArrType> il, Args&&... args) 
      ^
test.cpp:18:13: note: template argument deduction/substitution failed: 
test.cpp:37:51: note: couldn't deduce template parameter ‘ArrType’ 
    foo * foo3{ make_it<foo>({{1,1},{ 10,10 }}, 10) }; 
               ^
test.cpp:26:13: note: ValueType* make_it(Args&& ...) [with ValueType = foo; Args = {}] 
    ValueType * make_it(Args&&... args) 
       ^
test.cpp:26:13: note: candidate expects 0 arguments, 2 provided 

回答

4

統一初始化不適用於轉發。您不能直接轉發初始化參數,然後使用它們初始化某個對象。您可以初始化函數的參數,然後將其轉發給其他人,但不能轉發初始化參數。

Braced-init-lists(又名:{}的東西)不參與模板參數推導。這就是爲什麼當你這樣做時,你的foo3會出錯。編譯器無法知道你想要轉換成什麼類型​​,所以它失敗了。

即使您試圖將{{1, 1}, {10, 10}}存儲在auto變量中,也不會得到您想要的。 auto可以鍵入推斷初始化列表到initializer_list類型,但你會得到類似initializer_list<initializer_list<int>>的東西。

編譯器根本不會通過您的模板代碼,並找出您的真正意義。

+0

但我想知道爲什麼它不能使用未命名的結構,excalty作爲構造函數的作品。 initializer_list

+2

@ArturBac編譯器無法判斷「{{0,0},{1,1}}是否爲'std :: initializer_list >'或' std :: initializer_list >',或'std :: intializer_list ',... – Casey

+0

是的,我知道它不能確定它是結構體,所以它是完美轉發邏輯中的一個洞,我被設計爲轉發構造函數的參數,並且有些情況下它不能被使用。 如果我們告訴編譯器名爲struct(足以僅列出列表中的第一個結構體),那麼這將起作用: foo * foo3 {make_it ({foo :: pairs {1,1},{10,10}}} ,10)}; –

1

解決方案只適用於foo::pairs列表可接受嗎?

template<typename ValueType, typename... Args> 
ValueType * make_it(std::initializer_list<foo::pairs> il, Args&&... args) 
{ 
    ValueType * obj = new (allocfromstore(sizeof(ValueType))) ValueType(il, std::forward<Args>(args)...); 
    return obj; 
} 
+0

謝謝,我知道這一個,我想知道是否扣除參數std :: initializer列表可以與未命名的結構作爲參數。 –