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

时间:2014-10-15 09:43:58

标签: c++ unique-ptr c++14 initializer-list

我尝试使用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中有错误吗?或者我忽略了什么?

2 个答案:

答案 0 :(得分:30)

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声明的特殊规则,(正如我上面所说) do 实际上推导出std::initializer_list

答案 1 :(得分:3)

如果你准备输入一些额外的字符,你可以这样做:

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。除了我必须调整std::string - 文字并更改为make_shared之外,我还可以使用g ++ - 4.8.4。在Tmake_init_list的扣除工作正常。)

实际上,这是一个延伸吗?是否成功扣除了标准所要求的make_init_list