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

Calling initializer_list constructor via make_unique/make_shared

本文关键字:make initializer list 构造函数 调用 unique 通过 shared      更新时间:2023-10-16

我正试图使用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中是否存在错误?还是我忽略了什么?

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

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

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_listT的推导效果良好。)

事实上,这是分机吗?make_init_list扣减是否符合标准要求?