【问题标题】:Calling initializer_list constructor via make_unique/make_shared通过 make_unique/make_shared 调用 initializer_list 构造函数
【发布时间】: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 是一个可怕的错误设计。对此感到抱歉。

标签: c++ unique-ptr c++14 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"}
    猜你喜欢
    • 2016-04-03
    • 2021-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多