5

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
4

2 回答 2

5

统一初始化不适用于转发。您不能(直接)转发初始化参数,然后使用这些参数来初始化某些对象。您可以初始化函数的参数,然后将其转发给其他人,但您不能转发初始化参数。

Braced-init-lists (aka: the {}stuff) 不参与模板参数推导。这就是为什么您foo3在执行此操作时会出错。编译器不知道你想把它转换成什么类型​​,所以它失败了。

即使你试图存储{{1, 1}, {10, 10}}在一个auto变量中,你也不会得到你想要的。auto可以将支撑初始化列表类型推断为initializer_list类型,但您会得到类似initializer_list<initializer_list<int>>.

编译器根本不会检查您的模板代码并找出您真正想要的类型。

于 2013-08-01T18:01:12.253 回答
2

是否是仅适用于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;
}
于 2013-08-01T18:01:49.710 回答