我有一个类,其构造函数采用initializer_list
:
Foo::Foo(std::initializer_list<Bar*> bars)
如果我尝试使用大括号括起初始化列表 直接创建对象,则会正确推断出initializer_list
:
Foo f ({ &b }); // std::initializer_list<Bar*> correctly deduced
但是,当尝试执行相同的间接(使用可变参数函数模板 - 在本例中为make_unique
)时,编译器无法推导出initializer_list
:< / p>
std::make_unique<Foo>({ &b }); // std::initializer_list<Bar*> not deduced
错误输出:
错误:没有匹配函数来调用
‘make_unique(<brace-enclosed initializer list>)’
问题:
{ &b }
推断为initializer_list<Boo*>
?std::make_unique<Foo>({ &b })
?以下完整示例:
#include <initializer_list>
#include <memory>
struct Bar
{};
struct Foo
{
Foo(std::initializer_list<Bar*> bars)
{ }
};
int main()
{
Bar b;
// initializer_list able to be deduced from { &b }
Foo f ({ &b });
// initializer_list not able to be deduced from { &b }
std::unique_ptr<Foo> p = std::make_unique<Foo>({ &b });
(void)f;
return 0;
}
答案 0 :(得分:4)
支撑的初始化程序没有类型。当您致电make_unique
时,它会尝试推断出类型并失败。在这种情况下,您必须在调用时指定类型
std::make_unique<Foo>(std::initializer_list<Bar*>{ &b });
这将创建一个std::initializer_list<Bar*>
,编译器可以推导出它,并将其转发到Foo::Foo(std::initializer_list<Bar*> bars)
Foo f ({ &b });
工作的原因是编译器知道构造函数Foo(std::initializer_list<Bar*> bars)
,并且B*
的支撑初始化列表可以隐式转换为std::initializer_list<Bar*>
。没有类型扣除。
答案 1 :(得分:4)
make_unique
使用完美转发。
完美转发在以下方面并不完美:
无法转发初始化列表
它将NULL
或0
转换为整数,然后不能将其传递给指针类型的值。
它不知道它的参数是什么类型,所以你不能做需要知道它们类型的操作。举个例子:
struct Foo { int x; };
void some_funcion( Foo, Foo ) {};
template<class...Args>
decltype(auto) forwarding( Args&& ... args ) {
return some_function(std::forward<Args>(args)...);
}
致电some_function( {1}, {2} )
是合法的。它使用Foo
和{1}
构建{2}
。
呼叫forwarding( {1}, {2} )
不是。它在您调用forwarding
时不知道参数将是Foo
,因此无法构造它,并且它无法通过代码传递构造初始化列表(作为构造列表)不是变量或表达式。)
如果传递重载的函数名称,则无法在调用点处计算出哪个重载。并且一组重载不是一个值,所以你不能完美地推进它。
您无法通过位域。
它强制引用其参数,即使转发的目标没有。这&#34;使用&#34;一些静态const数据可能会导致程序在技术上形成错误。
无法转发对未知大小T(&)[]
的数组的引用。但是,您可以使用T*
来调用函数。
其中大约一半是从this comp.std.c++ thread中提取的,我记得有一次,我记得还有其他一些我无法回想起的问题。