2016-05-11 7 views
5

Siehe Should I use() or {} when forwarding arguments?. foo ist ein std::vector Klon.Warum gibt es keine std :: initializer_list Überladungen für std :: make_unique et al?

In N4140 wird unique.ptr.createstd::make_unique als so spezifiziert:

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

  • Bemerkungen: Diese Funktion ist in die Überladungsauflösung teilnehmen darf, es sei denn T kein Array ist.

  • Rückgabe: .

Das heißt Implementierungen sind erforderlich () zu verwenden, anstatt {} Objekte zu initialisieren. Als Beispiel wurde die folgende

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; 

Ausgänge 312 während, wenn {} (innen std::make_unique) verwendet würde 211 ausgegeben. Da Initialisierungslisten nicht abgeleitet werden können, muss std::initializer_list explizit übergeben werden, um das letztgenannte Ergebnis zu erhalten. Die Frage ist, warum wird keine Überlastung wie diese zur Verfügung gestellt?

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

Ausgänge 211.

Ich halte nicht die Gründe "Sie können es selbst schreiben" oder "Blähungen zu vermeiden den Standard", um sehr gute Gründe zu sein. Gibt es Nachteile bei der Bereitstellung dieser Überlast?

Antwort

2

Ich kenne nicht die komplette Geschichte, aber die wahrscheinlichste Antwort ist "niemand schlug es vor".

Beweise dafür wird durch die Tatsache unterstützt, dass std::make_unique wurde nur in C++ 14 hinzugefügt, noch std::unique_ptr in C++ 11 existierte.

Der Code und die Vorschläge für std::make_shared (die schließlich in make_unique gespiegelt wurde) existierten (in Boost) vor der initializer_list und die Initialisierung Syntax unterstützt es.

Eine Sache, die Sie jetzt tun könnten, ist es vorzuschlagen (und die Eckfälle auszuarbeiten, falls es welche gibt, z. B. SFINAE verwenden, um die Überladung zu entfernen, wenn der Zieltyp initializer_list nicht unterstützt).

+0

Ich glaube nicht, SFINAE notwendig ist. 'make_unique > (1, 73);' funktioniert völlig in Ordnung, wenn ich es aus dem Namespace nehme und 'namespace std;' verwende (um sicherzustellen, dass beide Überladungen sichtbar sind). Wenn jemand 'make_unique > ({1, 73});' das ist ihre Schuld. – user6319825

+0

@ user6319825.Ja, die SFINAE ist nicht essentiell, die Kompilierung scheitert in beiden Fällen, die Fehlermeldungen in einer SFINAE-Umgebung sind meiner Erfahrung nach "einfacher" zu diagnostizieren. – Niall

+0

Immer noch. Sie überlegten "neues T (std :: forward (args) ...") anstatt es der Implementierung zu überlassen, wie für [optional] (http://eel.is/c++draft/optional.object) .ctor # 23): "Initialisiert den enthaltenen Wert als ob direkt-nicht-list-initialisiert ein Objekt vom Typ' T' mit den Argumenten 'std :: forward (args)' .... "Das lässt mich denken, dass es da ist einige Diskussionen * irgendwo * zumindest für 'make_unique' spezifisch. – user6319825

0

Ich denke, es ist nur eine Vorlage Abzug Problem, siehe this answer.

Sie könnten diese versuchen:

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