2014-10-15 14 views
13

Próbuję użyć std::make_unique do zainicjowania klasy, której konstruktor ma otrzymać std::initializer_list. Oto minimalne przypadek:Wywołanie konstruktora initializer_list przez make_unique/make_shared

#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; 
} 

można zobaczyć na Coliru, że nie budować:

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"}); 

Więc jest make_unique podobno w stanie korzystać initializer_list s? Czy w GCC 4.9.1 występuje błąd? A może coś przeoczyłem?

+2

Utracone listy nie mogą zostać wyprowadzone przez odjęcie od szablonu. Wypróbuj 'make_unique (std :: initializer_list ({" Hello "," World "}))'. –

+0

@KerrekSB Cóż, to wygląda na odpowiedź: – Quentin

+0

Hm, czy to działa i czy to pomaga? –

Odpowiedz

20

std::make_unique to szablon funkcji, który dedukuje typy argumentów, które są przekazywane do konstruktora obiektu. Niestety, listy wzmocnione nie są dedukowalne (z wyjątkiem dla deklaracji auto), więc nie można utworzyć wystąpienia szablonu funkcji, gdy brak tego typu parametru.

Możesz nie używać std::make_unique, ale proszę nie idź tą trasą – powinieneś unikać nagich new s tak bardzo, jak tylko możesz, na litość boską. Albo można uczynić pracę typ odliczenia określając typ:

  • 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);

Ostatnia opcja wykorzystuje specjalną regułę auto deklaracji , który (jak wspomniałem powyżej) do w rzeczywistości wyprowadzić std::initializer_list.

2

Jeśli jesteś gotów wpisać kilka dodatkowych znaków, można to zrobić:

auto ptr = std::make_unique<Foo>(make_init_list({ "Hello"s , "World"s })); 

gdzie init_list jest zdefiniowany jako

template<typename T> 
std:: initializer_list<T> make_init_list (std:: initializer_list<T> && l) { 
    return l; 
} 

To pozwala na odliczenie występuje, i jest wygodny jeśli w kodzie jest wiele miejsc, musisz to zrobić. .

(działa na brzękiem 3.9 i gcc 6.2.0 Dostałem go do pracy na g ++ -. 4.8.4 również, z wyjątkiem musiałem podkręcić std::string -literal i przesiąść się make_shared Ale odliczenie T ciągu make_init_list pracował grzywna.)

Właściwie to rozszerzenie? Czy udana dedukcja dla standardu make_init_list jest wymagana przez standard, czy nie?