2015-07-08 7 views
15

Welches ist das richtige Verhalten für das folgende Programm?Unterschiedliches Compilerverhalten für Ausdruck: auto p {make_pointer()};

// example.cpp 

#include <iostream> 
#include <memory> 

struct Foo { 
    void Bar() const { 
    std::cout << "Foo::Bar()" << std::endl; 
    } 
}; 

std::shared_ptr<Foo> MakeFoo() { 
    return std::make_shared<Foo>(); 
} 

int main() { 
    auto p { MakeFoo() }; 
    p->Bar(); 
} 

Als ich es in meinem Linux RHEL 6.6 Workstation zu kompilieren, erhalte ich folgende Ergebnisse:

$ g++ -v 
gcc version 5.1.0 (GCC) 
$ g++ example.cpp -std=c++14 -Wall -Wextra -pedantic 
$ ./a.out 
Foo::Bar() 

aber

$ clang++ -v 
clang version 3.6.0 (trunk 217965) 
$ clang++ example.cpp -std=c++14 -Wall -Wextra -pedantic 
example.cpp:16:4: error: member reference type 'std::initializer_list<std::shared_ptr<Foo> >' is not a pointer; maybe you meant to use '.'? 
     p->Bar(); 
     ~^~ 
example.cpp:16:6: error: no member named 'Bar' in 'std::initializer_list<std::shared_ptr<Foo> >' 
     p->Bar(); 
     ~^
    2 errors generated. 

und

$ icpc -v 
icpc version 15.0.3 (gcc version 5.1.0 compatibility) 
$ icpc example.cpp -std=c++14 -Wall -Wextra -pedantic 
example.cpp(16): error: expression must have pointer type 
    p->Bar(); 
    ^
compilation aborted for example.cpp (code 2) 
+6

@ 0x499602D2: Das macht keinen Sinn. Der springende Punkt eines Sprachstandards ist es, Programm-Semantik eindeutig zu definieren. –

+0

@LightnessRacesinOrbit: Während ich zustimme, dass es hier nicht der Fall ist, gilt deine Aussage im Allgemeinen nicht: Zum einen hast du - vor allem in C und C++ - UB und IB, dann ist JEDES Verhalten korrekt (für IB es muss nur dokumentiert werden). Dann haben Sie optionales Verhalten (z. B. Kopie Elision) und schließlich kann sogar ein internationaler Standard Fehler enthalten, die zu mehrdeutigen Situationen führen können. – MikeMB

+1

@MikeMB: Fühlen Sie sich frei, mir ein Beispiel zu zeigen, wenn IB zu Compiler-Fehler in einer Implementierung, aber nicht anderen führt. Und UB zählt per Definition nicht. –

Antwort

15

Tl; DR

Dieses Verhalten unterliegt einem Vorschlag und einem Evolution Working Group-Problem. Es besteht eine gewisse Unklarheit darüber, ob dies als ein C++ 14-Fehler oder ein C++ 1z-Vorschlag betrachtet wird. Wenn es sich um einen C++ 14 Defekt handelt, ist das Verhalten von gcc für C++ 14 korrekt. Auf der anderen Seite, wenn dies wirklich ein C++ 1z-Vorschlag ist, dann zeigen clang und icpc korrektes Verhalten.

Einzelheiten

Es ist wie diesem Fall sieht durch N3681 abgedeckt, die sagt:

Auto und verspannt initializers ein Lehrbarkeit Problem verursachen; Wir wollen lehren Menschen zu einheitlichen Initialisierung zu verwenden, aber wir müssen speziell Programmierer sagen Klammern mit Auto zu vermeiden. In C++ 14 haben wir jetzt mehr Fälle, in denen auto und geschweifte Klammern problematisch sind; Rückgabetyp Abzug für Funktionen teilweise vermeidet das Problem, seit eine Klammer-Liste nicht funktioniert, da es kein Ausdruck ist. Wenn Sie jedoch eine von einem abgestuften Initialisierer initialisierte automatische Variable zurückgeben, wird eine Initialisiererliste zurückgegeben, die zu undefiniertem Verhalten führt. Lambda init Captures haben das gleiche Problem. Dieses Dokument schlägt vor, eine Klammer-initialisierte Auto, um nicht auf eine Initialisierungsliste zu schließen, und verbiegende initialisierte Auto für Fälle, in denen die Klammer-Initialisierung mehr als ein Element hat.

und bietet die folgenden Beispiele:

auto x = foo(); // copy-initialization 
auto x{foo}; // direct-initialization, initializes an initializer_list 
int x = foo(); // copy-initialization 
int x{foo}; // direct-initialization 

So ist denke ich Klirren momentan richtig, die neueste Version von Klirren bietet diese Warnung:

Warnung: Die direkte Listeninitialisierung einer Variablen mit einem abgeleiteten Typ ändert ihre Bedeutung in einer zukünftigen Version von Clang; ein '=' zu legen Sie eine Änderung im Verhalten [-Wfuture-compat]

Von EWG issue 161 vermeiden, dass N3922 für diese angenommen wurde.

Wie Praetorian stellt der Vorschlag empfiehlt es sich um einen C++ 14 Defekte:

Aus Richtung EWG ist, dass wir 14 dies ein Defekt in C++ betrachten.

aber clang C++1z implementation status notes dies als ein C++ 1z-Vorschlag, der nicht implementiert ist.

Also, wenn dies ein C++ 14 Defekt ist, würde das gcc korrekt machen, aber es ist mir nicht klar, ob das wirklich ein Defekt oder ein Vorschlag ist.

T.C. weist in einem comment here darauf hin, dass es seems like the clang developers tun soll, dies zurück zu portieren. Es ist nicht passiert und es ist nicht klar warum.

+3

Scoot Myers spricht über diese [hier] (https://channel9.msdn.com/Events/CPP/C-PP-Con-2014/Type-Deduction-and-Wy-You-Care) bei etwa 30 Minuten in. – NathanOliver

+1

Interessant ist, dass N3922 dies einen C++ 14 Defekt nennt (was ich auch dachte), aber clang [claims] (http://clang.llvm.org/cxx_status.html) ist ein C++ 1z ändern (Suche nach N3922 auf dieser Seite). gcc-5.1 akzeptiert das Beispiel auch im OP im C++ 11-Modus. – Praetorian

+0

@Praetorian guten Punkt, ich habe mich darüber gewundert, änderte ich meine Antwort zu erwähnen, dass. –