2016-05-11 16 views
5

Vedere Should I use() or {} when forwarding arguments?. foo è un clone std::vector.Perché non esistono std :: initializer_list overload per std :: make_unique et al?

In N4140, unique.ptr.createstd::make_unique è specificato come così:

template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);

  • Commento: Questa funzione non partecipa risoluzione sovraccarico meno T non è un array.

  • Resi: unique_ptr<T>(new T(std::forward<Args>(args)...)).

Ciò significa implementazioni sono obbligati a ricorrere () anziché {} inizializzare oggetti. Come esempio, la seguente

auto s1 = std::make_unique<foo>(3, 1).get()->size(); 
auto s2 = std::make_unique<foo>(1).get()->size(); 
auto s3 = std::make_unique<foo>(2).get()->size(); 
std::cout << s1 << s2 << s3; 

uscite 312 mentre se {} (all'interno std::make_unique) è stato utilizzato 211 sarebbe uscita. Poiché gli elenchi di inizializzazione non possono essere dedotti, è necessario passare esplicitamente il std::initializer_list per ottenere il risultato finale. La domanda è, perché non è un sovraccarico come questo fornito?

namespace test 
{ 

template <class T, class Deduce> 
std::unique_ptr<T> make_unique(std::initializer_list<Deduce> li) 
{ 
    return ::std::make_unique<T>(li); 
} 

}; 

int main() 
{ 
    auto p1 = test::make_unique<foo>({3, 1}).get()->size(); 
    auto p2 = test::make_unique<foo>({1}).get()->size(); 
    auto p3 = test::make_unique<foo>({2}).get()->size(); 
    std::cout << p1 << p2 << p3; 
} 

Uscite 211.

Non considero i motivi per cui "è possibile scrivere da soli" o "per evitare il rigonfiamento dello standard". C'è qualche svantaggio nel fornire questo sovraccarico?

risposta

2

Non conosco la cronologia completa, ma la risposta più probabile è "nessuno lo ha proposto".

La prova è supportata dal fatto che std::make_unique è stato aggiunto solo in C++ 14, tuttavia std::unique_ptr esisteva in C++ 11.

Il codice e le proposte di std::make_shared (che fu poi specchia in make_unique) esistevano (in boost) prima della initializer_list e la sintassi inizializzazione sostenerlo.

Una cosa che potresti fare ora è di proporla (e risolvere i casi d'angolo se ce ne sono, ad esempio usa SFINAE per rimuovere il sovraccarico se il tipo di destinazione non supporta lo initializer_list).

+0

Non credo SFINAE è necessario. 'make_unique > (1, 73);' funziona perfettamente bene se lo tolgo dal namespace e faccio 'using namespace std;' (per assicurarsi che entrambi gli overload siano visibili). Se qualcuno fa "make_unique > ({1, 73});" è colpa loro. – user6319825

+0

@ user6319825.Sì, SFINAE non è essenziale, la compilazione fallisce in entrambi i casi, solo nella mia esperienza i messaggi di errore in un ambiente SFINAE sono "più facili" da diagnosticare. – Niall

+0

Ancora. Hanno deliberato di dire "nuovo T (std :: forward (args) ...)" invece di lasciarlo all'implementazione come per [opzionale] (http://eel.is/c++draft/optional.object .ctor # 23): "Inizializza il valore contenuto come se direct-non-list-inizializzando un oggetto di tipo' T' con gli argomenti 'std :: forward (args)' .... "Questo mi fa pensare che ci sia qualche discussione * da qualche parte * almeno per 'make_unique' in particolare. – user6319825

0

Penso che sia solo un problema di deduzione modello, vedere this answer.

Si potrebbe provare questi:

int main() 
{ 
    auto p1 = std::make_unique<foo>(std::initializer_list<int>{3, 1}).get()->size(); 
    auto p2 = std::make_unique<foo>(foo{1}).get()->size(); 
    auto l3 = {2}; 
    auto p3 = std::make_unique<foo>(l3).get()->size(); 
    std::cout << p1 << p2 << p3; 
} 
Problemi correlati