2013-07-10 15 views
14

Ich verstehe, dass ein verspannt initializer gegeben, auto eine Art std::initializer_list ableiten wird, während Abzug Vorlagentyp fehl:Warum unterscheiden sich Auto- und Schablonentypabzüge für starre Initialisierer?

auto var = { 1, 2, 3 }; // type deduced as std::initializer_list<int> 

template<class T> void f(T parameter); 

f({ 1, 2, 3 });   // doesn't compile; type deduction fails 

ich auch wissen, wo diese in der C++ 11-Standard spezifiziert ist: 14.8. 2.5/5 Punkt 5:

[It's a non-deduced context if the program has] A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter does not have std::initializer_list or reference to possibly cv-qualified std::initializer_list type. [ Example:

template void g(T);

g({1,2,3}); // error: no argument deduced for T

end example ]

Was ich weiß, oder nicht verstehen Deshalb dieser Unterschied in der Art Abzug Verhalten besteht. Die Spezifikation in der C++ 14-CD ist die gleiche wie in C++ 11, daher sieht das Standardisierungsgremium vermutlich das Verhalten von C++ 11 nicht als einen Defekt an.

Weiß jemand, warum einen Typ für einen abgestützten Initialisierer ableitet, aber Vorlagen nicht erlaubt sind? Während spekulative Erklärungen der Form "das könnte der Grund sein" interessant sind, interessiere ich mich besonders für Erklärungen von Leuten, die wissen warum der Standard so geschrieben wurde, wie es war.

+0

Es wurde kürzlich eine weitere Frage zu SO gestellt, was Sie herausgefunden haben. Es könnte einige Gründe dafür haben. – chris

+2

Ok, habe es gefunden. Die einzige wirkliche warum Diskussion ist ein Kommentar, aber Sie können einen Blick darauf werfen: http://stackoverflow.com/questions/17496268/type-inference-with-rvalue-initializer-list – chris

+3

Zitat aus [Scott Meyers] (http://scottmeyers.blogspot.cz/2013/07/when-decltype-meets-auto.html): "* Ich habe keine Ahnung, warum Abzüge für 'auto' eingeben und für Vorlagen nicht identisch ist. Wenn Sie wissen, bitte sagen Sie mir! * ". –

Antwort

0

Zunächst einmal ist es "spekulative Erklärungen der Form" das könnte der Grund sein "" wie Sie es nennen.

{1,2,3} ist nicht nur std::initializer_list<int> sondern auch ermöglichen Typen ohne Konstruktor initialisieren. Zum Beispiel:

#include <initializer_list> 

struct x{ 
    int a,b,c; 
}; 

void f(x){ 

} 
int main() { 
    f({1,2,3}); 
} 

ist der richtige Code. Um zu zeigen, dass es nicht initializer_list lassen ist sehen die den folgenden Code:

#include <initializer_list> 

struct x{int a,b,c;}; 

void f(x){ 

} 
int main() { 
    auto il = {1, 2, 3}; 
    f(il); 
} 

Fehler ist: „Was ist der Unterschied“

prog.cpp: In function ‘int main()’: 
prog.cpp:10:9: error: could not convert ‘il’ from ‘std::initializer_list<int>’ to ‘x’ 

Und jetzt auf die Frage

in auto x = {1, 2, 3}; Code ist es OK-Typen zu bestimmen, da Codierer ausdrücklich gesagt: „Es ist nicht wichtig, was es geben wird“ mit auto

Während bei Funktionsvorlage er sicher sein kann, dass er verschiedene Arten verwendet. Und es ist gut, Fehler in mehrdeutigen Fällen zu verhindern (Es scheint nicht wie C++ - Stil, durch).

Besonders schlimm wird es sein, wenn es 1 Funktion gab f(x) und dann wurde es zu Vorlage eins geändert. Programmierer schrieb, um es als x zu verwenden, und nachdem er neue Funktion für anderen Typ hinzugefügt hat, ändert er sich leicht, um völlig anderes anzurufen.

+1

Ich verstehe nicht, wie "auto" bedeutet "es ist nicht wichtig, was der Typ ist", aber sagen "Vorlage " bedeutet etwas anderes. In beiden Fällen besteht das Risiko, dass der abgeleitete Typ möglicherweise nicht dem entspricht, was der Programmierer beabsichtigt hat. – KnowItAllWannabe

+0

Ich verstehe den zweiten Code nicht. Sie schreiben "Um zu zeigen, dass es nicht Initializer-Liste ist", aber in dem Beispiel '{1,2,3}' ist eine Initialisierungsliste, daher der Fehler ... – user463035818

+0

Ich meine, ich zeige, dass in ersten Code ist es nicht initializer_list. Denn wenn es initialzer_list ist, funktioniert es nicht – RiaD

13

Es gibt zwei wichtige Gründe für die Vorlagen keinen Abzug zu tun (die beide, die mich in einem Gespräch mit dem Mann verantwortlich erinnern)

  • Bedenken über die zukünftigen Spracherweiterungen (es gibt mehrere Bedeutungen könnten Sie erfinden - was ist, wenn wir eine perfekte Weiterleitung für verspannte Init-Listen-Funktionsargumente einführen wollten?)

  • Die Klammern manchmal wirksam können einen Funktionsparameter initialisieren, die

template<typename T> 
void assign(T &d, const T& s); 
int main() { 
    vector<int> v; 
    assign(v, { 1, 2, 3 }); 
} 

Wenn T auf der rechten Seite zu initializer_list<int> aber auf der linken Seite zu vector<int> abgeleitet würde abhängig ist, das würde wegen einer widersprüchlichen Argumentableitung nicht funktionieren.

Der Abzug für auto bis initializer_list<T> ist umstritten. Es gibt einen Vorschlag für C++ - nach-14, um es zu entfernen (und die Initialisierung mit { } oder {a, b} zu verbieten, und {a} auf den Typ a abzuleiten).