2014-10-15 16 views
13

Sto provando a utilizzare std::make_unique per installare una classe il cui costruttore deve ricevere un std::initializer_list. Ecco un caso minimo:Chiamare il costruttore initializer_list tramite 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; 
} 

Si può vedere su Coliru che non costruisce:

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

Quindi, è make_unique riferito in grado di utilizzare initializer_list s? C'è un bug in GCC 4.9.1? O ho trascurato qualcosa?

+2

Gli elenchi rinforzati non possono essere dedotti dalla deduzione degli argomenti del modello. Prova 'make_unique (std :: initializer_list ({" Hello "," Mondo "}))'. –

+0

@KerrekSB Bene, mi sembra una risposta :) – Quentin

+0

Hm, funziona e aiuta? –

risposta

20

std::make_unique è un modello di funzione che deduce i tipi di argomento che vengono passati al costruttore dell'oggetto. Sfortunatamente, le liste rinforzate non sono deducibili (con un'eccezione per le dichiarazioni auto) e quindi non è possibile creare un'istanza del modello di funzione quando quel tipo di parametro mancante.

È possibile o non utilizzare std::make_unique, ma per favore non seguire questa strada – si dovrebbe evitare di nudo new s per quanto è possibile, per il bene dei bambini. Oppure si può fare il lavoro di tipo detrazione specificando il tipo:

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

L'ultima opzione utilizza la regola speciale per auto dichiarazioni , che (come ho accennato sopra) do infatti deduce uno std::initializer_list.

2

Se siete pronti a digitare alcuni caratteri in più, si può fare questo:

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

dove init_list è definito come

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

Questo permette la detrazione a verificarsi, ed è conveniente se ci sono molti posti nel codice devi farlo. .

(Opere su clang 3.9 e 6.2.0 gcc ho preso a lavorare su g ++ -. 4.8.4 anche, tranne che ho dovuto modificare il -literal std::string e passare alla make_shared Ma la detrazione di T all'interno make_init_list lavorato bene.)

In realtà, si tratta di un'estensione? La detrazione corretta per lo standard make_init_list è richiesta dallo standard o no?

Problemi correlati