Вызов конструктора initializer_list через make_unique/make_shared
Я пытаюсь использовать 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? Или я что-то упустил?
Ответы
Ответ 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
, которые (как я намекнул выше) действительно выводят std::initializer_list
.
Ответ 2
Если вы готовы ввести несколько дополнительных символов, вы можете сделать это:
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
. Но вывод T
в пределах make_init_list
работал нормально.)
Собственно, это это расширение? Успешная вычет для make_init_list
, требуемая стандартом, или нет?