完美转发,可变参数模板,initializer_list - 在一起

时间:2013-08-01 17:11:54

标签: c++11

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

2 个答案:

答案 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;
}