通过 make_unique/make_shared 调用 initializer_list 构造函数
Posted
技术标签:
【中文标题】通过 make_unique/make_shared 调用 initializer_list 构造函数【英文标题】:Calling initializer_list constructor via make_unique/make_shared 【发布时间】:2014-12-10 08:08:14 【问题描述】:我正在尝试使用std::make_unique
来实例化一个类,其构造函数将接收std::initializer_list
。这是一个最小的案例:
#include <string>
#include <vector>
#include <initializer_list>
#include <memory>
struct Foo
Foo(std::initializer_list<std::string> strings) : strings(strings)
std::vector<std::string> strings;
;
int main(int, char**)
auto ptr = std::make_unique<Foo>("Hello", "World");
return 0;
您可以在 Coliru 上看到它没有构建:
main.cpp:14:56: error: no matching function for call to 'make_unique(<brace-enclosed initializer list>)'
auto ptr = std::make_unique<Foo>("Hello", "World");
那么,据说make_unique
无法使用initializer_list
s 吗? GCC 4.9.1 中是否存在错误?还是我忽略了什么?
【问题讨论】:
不能通过模板参数推导推导出括号列表。试试make_unique<Foo>(std::initializer_list<std::string>("Hello", "World"))
。
@KerrekSB 好吧,这看起来像是对我的回答 :)
嗯,它有用吗,有帮助吗?
@KerrekSB 是的!但是,那个语法。 initializer_list
s 绝对是个奇怪的小玩意儿。在那种特殊情况下,我想我会从new
调用中构造unique_ptr
。
这很遗憾,但可以理解。 std::initializer_list
是一个可怕的错误设计。对此感到抱歉。
【参考方案1】:
如果您准备输入一些额外的字符,您可以这样做:
auto ptr = std::make_unique<Foo>( make_init_list( "Hello"s , "World"s ));
init_list
定义为
template<typename T>
std:: initializer_list<T> make_init_list ( std:: initializer_list<T> && l )
return l;
这样可以进行推理,如果代码中有很多地方必须这样做,则很方便。
(适用于 clang 3.9 和 gcc 6.2.0。我也让它在 g++-4.8.4 上工作,除了我必须调整 std::string
-literal 并更改为 make_shared
。但是扣除了 @ make_init_list
内的 987654326@ 工作正常。)
实际上,这是一个扩展? make_init_list
的扣费成功是否符合标准?
【讨论】:
【参考方案2】:std::make_unique
是一个函数模板,它推断传递给对象构造函数的参数类型。不幸的是,花括号列表是不可推导的(auto
声明除外),因此当缺少参数类型时,您无法实例化函数模板。
你也可以不使用std::make_unique
,但请不要走那条路——为了孩子们,你应该尽可能避免赤裸裸的new
s。或者您可以通过指定类型来进行类型推导:
std::make_unique<Foo>(std::initializer_list<std::string>("Hello", "World"))
std::make_unique<Foo, std::initializer_list<std::string>>("Hello", "World")
auto il = "Hello"s, "World"s ; auto ptr = std::make_unique<Foo>(il);
最后一个选项使用 auto
声明的特殊规则,(正如我上面暗示的)确实实际上推导出了 std::initializer_list
。
【讨论】:
你说std::initializer_list<std::string>("Hello", "World")
,为什么不是std::initializer_list<std::string>"Hello", "World"
?以上是关于通过 make_unique/make_shared 调用 initializer_list 构造函数的主要内容,如果未能解决你的问题,请参考以下文章
java是通过值传递,也就是通过拷贝传递——通过方法操作不同类型的变量加深理解