通过 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_lists 吗? GCC 4.9.1 中是否存在错误?还是我忽略了什么?

【问题讨论】:

不能通过模板参数推导推导出括号列表。试试make_unique&lt;Foo&gt;(std::initializer_list&lt;std::string&gt;("Hello", "World")) @KerrekSB 好吧,这看起来像是对我的回答 :) 嗯,它有用吗,有帮助吗? @KerrekSB 是的!但是,那个语法。 initializer_lists 绝对是个奇怪的小玩意儿。在那种特殊情况下,我想我会从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,但请不要走那条路——为了孩子们,你应该尽可能避免赤裸裸的news。或者您可以通过指定类型来进行类型推导:

std::make_unique&lt;Foo&gt;(std::initializer_list&lt;std::string&gt;("Hello", "World"))

std::make_unique&lt;Foo, std::initializer_list&lt;std::string&gt;&gt;("Hello", "World")

auto il = "Hello"s, "World"s ; auto ptr = std::make_unique&lt;Foo&gt;(il);

最后一个选项使用 auto 声明的特殊规则,(正如我上面暗示的)确实实际上推导出了 std::initializer_list

【讨论】:

你说std::initializer_list&lt;std::string&gt;("Hello", "World"),为什么不是std::initializer_list&lt;std::string&gt;"Hello", "World"

以上是关于通过 make_unique/make_shared 调用 initializer_list 构造函数的主要内容,如果未能解决你的问题,请参考以下文章

下拉框多选框单选框 通过TagHelper绑定数据

酶:测试孩子通过安装渲染失败,但通过浅时通过

java是通过值传递,也就是通过拷贝传递——通过方法操作不同类型的变量加深理解

通过代码进行 Spring 配置与通过注释进行配置

如何理解“不要通过共享内存来通信,而应该通过通信来共享内存”?

通过邮递员通过 API 使用 Rails 主动存储上传文件(.pdf、.jpg 等)? (不通过 Rails 视图)