2014-10-12 5 views
6

In seiner CppCon 2014 talke "Type Deduction and Why You Care" wirft Scott Meyers die Frage auf, warum es eine spezielle Regel über und starre Initialisierer im C++ 11/C++ 14 Standard gibt (seine Frage beginnt at 36m05s).Warum gibt es in C++ 11/C++ 14 eine spezielle Typableitungsregel für Auto und Brained-Initialisierer?

Die Semantik von Auto in Kombination mit einer Braced-Init-Liste ist in §7.1.6.4/6 definiert.


Ich dachte darüber nach und konnte auch keinen Anwendungsfall finden. Das Nächste, was ich bisher gesehen habe, ist ein Beispiel, wo Bjarne Stroustrup es benutzt hat.

In seinem Cpp 2014 talk "Make Simple Tasks Simple!" verwendet er einmal auto, um Initialisierer zu erfassen (aber nur als Workaround).

Hier ist der Code (Teil des Schlittens 30, at 37m10s):

// auto ss1 = collect({ 1, 2, 3, 4, 5, 6 }, odd); // error: Bummer! 
    auto lst = { 1, 2, 3, 4, 5, 6 }; 
    auto ss2 = collect(lst, odd); // {1,3,5} 

Aber beachten Sie, dass es nur eine Abhilfe ist. Er erwähnte, dass es nicht notwendig sein sollte. Stattdessen würde er es vorziehen, die Argumente direkt an die Funktion zu übergeben. Also kann es nicht wirklich als eine gute Motivation für auto und Initialisierungslisten dienen.


Mein Verständnis von C++ ist nicht tief genug, um die Nachteile des damit initializer-Listen in Bjarne Beispiel zu beurteilen, wie er vorschlägt. Jedenfalls würde es in diesem Fall die Notwendigkeit für auto vermeiden.

Also, ist auto und Initialisierungsliste nur ein Workaround für etwas, das besser hätte gelöst werden können? Oder gibt es gute Beispiele, wo die Regel für den zusätzlichen automatischen Abzug in §7.1.6.4/6 nützlich ist?

+0

Ich bin mir ziemlich sicher, dass es einen C++ 1z-Vorschlag gibt, um 'auto x = {expr};' den Typ von 'expr' zu verwenden (minus einen nicht eingeklammerten Komma-Operator). Ich bin mir nicht sicher, welchen anderen Typ ich für eine vollständige Liste verwenden soll. – chris

+0

@christ Ich denke du meinst N3922. Scott Meyers erwähnt das auch. Visual Studio implementiert es bereits, obwohl es nicht Teil von C++ 14 ist. Hier ist der Link: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3922.html –

+0

Ah, das ist der eine. Obwohl ich * irgendwie * mit dem allgemeinen aufgrund dieser Verwendung nicht einverstanden bin. Ich würde es wirklich vorziehen, dass sie schlecht gebildet sind und Initialisierungslisten in Funktionen ohne die zusätzliche Zeile übertragen werden können. – chris

Antwort

8

Das Grundprinzip ist in N2640, die aus einer verspannten Initialisiererliste im allgemeinen Abzug von einem einfachen Typ-Parametern verbieten wollten:

template<class T> 
void inc(T, int); // (1) 

template<class T> 
void inc(std::initializer_list<T>, long); // (2) 

inc({1, 2, 3}, 3); // Calls (2). (If deduction had succeeded 
        // for (1), (1) would have been called — a 
        // surprise.) 

Aber geschnitzt eine besondere Ausnahme für auto:

Auf der anderen Seite, in der Lage, eine initializer_list<X> für T abzuleiten ist attraktiv ve zu ermöglichen:

auto x = { 1, 1, 2, 3, 5 }; 
f(x); 
g(x); 

, die wünschenswerte Verhalten seit Beginn der EWG Diskussionen über initializer Listen gehalten wurde. Statt mit einer cleveren Ableitungsregel für einen Parametertyp T, der mit einer {} -list (einer Option, die wir in früheren Skizzen und Entwürfen dieses Papiers verfolgt haben) übereinstimmten, bevorzugen wir jetzt, dies mit einem speziellen Fall zu handhaben "auto" Variable Abzug, wenn der Initialisierer eine {} -Liste ist. Das heißt, für den spezifischen Fall einer Variablen, die mit einem Spezifizierer "automatisch" und einem Initialisierer {} -list deklariert ist, wird das "Auto" wie für eine Funktion f(initializer_list<T>) statt wie für eine Funktion f(T) abgeleitet.

2

Scott Meyers adressiert das Thema in einem Blog-Post: Why auto deduces std::initializer_list for a braced initializer

Wie T. C. Antwort, es bezieht sich auch auf N2640. Die spezielle Abtragungsregel wird hinzugefügt Code wie folgt zu ermöglichen, zu arbeiten:

auto x = { 1, 1, 2, 3, 5 }; 
f(x); 
g(x); 

In Blog-Post, Scott zitiert die folgende Erklärung von James Hopkin:

Die kurze Geschichte ist, dass N2640 die vorgeschlagene Sonderfall, dass Auto abgestützte Initialisierer als initializer_listen ableiten sollte, ohne zu realisieren, dass dies die Initialisierung der Initialisierung vereitelt (zB macht es int x{7}; und auto x{7}; sehr unterschiedlich). N3922 behebt das, indem (natürlich!) Ein anderer Spezialfall eingeführt wird: Single-Parameter-Bracing-Initialisierer haben ihre eigene Regel.

Etwas mehr Details: N2640 versucht, Argumentabzug einfach beizubehalten, versucht jedoch, einen gestaffelten Initialisierer an zwei oder mehr Funktionen zu übergeben, indem er einem Auto zugewiesen wird. Dies wurde zu einer Formulierung in N2672. Beachten Sie, dass der vorherige Entwurf von Stroustrup in N2532 die Ableitung von initializer_lists für unbeschränkte Template-Parameter und auto ermöglicht, was zwar konsistenter ist, aber auch die einheitliche Initialisierung durchbricht.

Nichts davon erklärt, warum N3922 nicht nur den Sonderfall für Auto entfernt. Das hätte nicht zu stillen Änderungen an der Bedeutung des Codes geführt und hätte die Sprache vereinfacht.