通过make_unique/make_shared调用initializer_list构造函数

41

我正在尝试使用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吗?GCC 4.9.1中是否存在错误?还是我漏看了什么?


4
花括号列表不能通过模板参数推导进行推断。尝试使用 make_unique<Foo>(std::initializer_list<std::string>({"Hello", "World"})) - Kerrek SB
嗯,它能工作吗?它有帮助吗? - Kerrek SB
1
@KerrekSB 是的,它可以!但是,那种语法让人不舒服。 initializer_list 绝对是奇怪的小玩意儿。在这种特定情况下,我认为我只需从一个 new 调用中构造 unique_ptr - Quentin
3
很遗憾,但可以理解。std::initializer_list 是一个非常糟糕的设计。对此感到抱歉。 - Kerrek SB
嘿,试试这个:std::make_unique<Foo, std::initializer_list<std::string>>({"Hello", "World"}) - Kerrek SB
显示剩余11条评论
2个回答

61

std::make_unique是一个函数模板,它推断传递给对象构造函数的参数类型。可惜的是,花括号列表不可推导(auto声明除外),所以当缺少参数类型时,无法实例化函数模板。

你可以选择不使用std::make_unique,但请不要这么做-为了孩子们的未来,请尽量避免使用裸指针new。或者通过指定类型使类型推断生效:

  • 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


1
你说 std::initializer_list<std::string>({"Hello", "World"}),为什么不用 std::initializer_list<std::string>{"Hello", "World"} - Kegan Thorrez

10
如果您愿意多打几个字,可以这样做:
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上实现了它,除了我必须调整文字并改为make_shared外。但是,在make_init_list内的T的推导正常工作。) 实际上,这是一种扩展吗?是否需要标准化成功推断make_init_list?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接