gcc 4.8.1& clang 3.3,c ++ 11功能齐全, 我需要在构造像make_shared / c ++ 14 make_unique这样的元素的函数中转发args。但我有类型扣除/转发初始化列表/数组
的问题我需要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将因clang 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
答案 0 :(得分:5)
统一初始化不适用于转发。您无法转发初始化参数(直接),然后使用它们初始化某些对象。您可以初始化函数的参数,然后将其转发给其他人,但不能转发初始化参数。
Braced-init-lists(又名:{}
内容)不参与模板参数推断。这就是为什么你foo3
出错时会出错的原因。编译器无法知道您希望将其转换为什么类型,因此失败。
即使您尝试将{{1, 1}, {10, 10}}
存储在auto
变量中,也无法获得所需内容。 auto
可以将支持初始化列表的类型推导为initializer_list
类型,但您会得到类似initializer_list<initializer_list<int>>
的内容。
编译器根本不会查看您的模板代码并找出您真正想要的类型。
答案 1 :(得分: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;
}