2012-12-27 8 views
19

Im other topic gab @Dietmar diese Lösung:Auftrag der Auswertung der Elemente in Liste-Initialisierung

template <typename... T> 
std::tuple<T...> parse(std::istream& in) 
{ 
    return std::tuple<T...>{ T(in)... }; 
} 

dass die besagt,

Die Verwendung von Klammer Initialisierung funktioniert, weil die Reihenfolge der Auswertung der Argumente in einer Klammerinitialisierungsliste ist die Reihenfolge, in der sie erscheinen. (Betont Mine)

Der entsprechende Text aus dem C++ Standard (n3485) ist,

Innerhalb der Initialisierer-Liste einer verspannt-init-Liste, die Initialisierer-Klauseln auch etwaig, die zur Folge hat aus Pack-Expansionen (14.5.3) werden in der Reihenfolge ausgewertet, in der sie auftreten. Das heißt, jede Wertberechnung und jeder Nebeneffekt, der einer gegebenen Initialisierungsklausel zugeordnet ist, wird vor jeder Wertberechnung und jedem Nebeneffekt, der mit einer Initialisierungsklausel verknüpft ist, die ihr folgt, in der kommagetrennten Liste der Initialisierungsliste sequenziert. [Anmerkung: Diese Bewertungsordnung gilt unabhängig von der Semantik der Initialisierung; zum Beispiel gilt es, wenn die Elemente der Initialisiererliste als Argumente eines Konstruktoraufrufs interpretiert werden, obwohl normalerweise keine Sequenzbeschränkungen für die Argumente eines Aufrufs bestehen. -Ende note]


Also habe ich versucht, dies mit dem folgenden Code zu testen:

template<int N> 
struct A 
{ 
    std::string data; 
    A(std::istream & stream) { stream >> data; } 
    friend std::ostream& operator<<(std::ostream & out, A<N> const & a) 
    { 
     return out << "A"<<N<<"::data = " << a.data; 
    } 
}; 
typedef A<1> A1; 
typedef A<2> A2; 

template<typename ...Args> 
void test(std::istream & stream) 
{ 
    std::tuple<Args...> args { Args(stream)... }; 
    std::cout << std::get<0>(args) << std::endl; 
    std::cout << std::get<1>(args) << std::endl; 
} 

int main() 
{ 
    std::stringstream ss("A1 A2"); 
    test<A1,A2>(ss); 
} 

Erwartete Ausgabe:

A1::data = A1 
A2::data = A2 

tatsächlicher Ausgang:

A1::data = A2 
A2::data = A1 

Habe ich in meinem Testcode etwas falsch gemacht? Ich habe meinen Code folgendermaßen geändert:

std::stringstream ss("A1 A2"); 
std::tuple<A1,A2> args{A1(ss), A2(ss)}; 
std::cout << std::get<0>(args) << std::endl; 
std::cout << std::get<1>(args) << std::endl 

Gleicher Ausgang wie zuvor. Ich habe meinen Code mit MinGW (GCC) 4.7.0 und 4.7.2 getestet. Selbst Ideon gibt this output.

Ist es ein Fehler im Compiler?

+0

clang-3.2 generiert die erwartete Ausgabe. Vielleicht ist es ein GCC-Bug? –

+4

Dies ist ein GCC-Fehler. Clang bekommt es richtig. – Xeo

+4

Was erwarten Sie von uns? "Ja, es ist ein Fehler wegen des Zitats, das du gibst". Ist das heute nicht zweimal gesagt worden?Sowohl in der Frage von @Dietmar als auch in der Frage Dietmar wurden Hinweise, Zitate und Beispiele gegeben, die besagen, dass die Reihenfolge von links nach rechts ist. –

Antwort

8

Beantworten meiner eigenen Frage. Das Löschen der Frage wäre keine gute Idee, da jemand in Zukunft vielleicht dieselbe Frage haben könnte.

Ja. Es ist ein Fehler im GCC-Compiler.

von @Johannes Schaub Kommentar zu der Frage gemacht.

+2

Beachten Sie, dass Microsoft Visual Studio 12 (2013) den gleichen Fehler aufweist, den ich gerade unter https://connect.microsoft.com/ gemeldet habe. VisualStudio/feedbackdetail/view/976911/braced-Initialisierer-Liste-nicht-ausgewertet-links-nach-rechts – Oberon

+0

Gibt es eine Arbeit für MSVC? – Ram

+0

Dies wird in MSVC 2015 Update 2 behoben (https://blogs.msdn.microsoft.com/vcblog/2016/02/11/compiler-improvements-in-vs-2015-update-2/) –

Verwandte Themen