2015-02-02 6 views
25

Jemand hatte asked den anderen Tag warum etwas mit clang kompiliert, aber nicht mit gcc. Ich verstand intuitiv, was vor sich ging und konnte der Person helfen, aber es brachte mich dazu, mich zu fragen, welcher Compiler nach dem Standard korrekt war. Hier ist eine eingekocht Version des Codes:g ++ lehnt ab, clang ++ akzeptiert: foo (x) ("bar") ("baz");

#include <iostream> 
#include <string> 

class foo 
{ 
public: 
    foo(const std::string& x): 
     name(x) 
    { } 
    foo& operator()(const std::string& x) 
    { 
     std::cout << name << ": " << x << std::endl; 
     return (*this); 
    } 
    std::string name; 
}; 

int main() 
{ 
    std::string x = "foo"; 
    foo(x)("bar")("baz"); 
    return 0; 
} 

Dies kompiliert fein mit Klirren ++, aber g ++ gibt die folgenden Fehler:

runme.cpp: In function ‘int main()’: 
runme.cpp:21:11: error: conflicting declaration ‘foo x’ 
    foo(x)("bar")("baz"); 
     ^
runme.cpp:20:17: error: ‘x’ has a previous declaration as ‘std::string x’ 
    std::string x = "foo"; 

Wenn ich ein Paar von Klammern in Zeile 21, fügen Sie g ++ ist glücklich:

foo x ("bar")("baz"); 
:

(foo(x))("bar")("baz"); 

Mit anderen Worten, g ++ diese Zeile als interpretiert

Ich denke, es ist ein Fehler in g ++, aber ich wollte die Standard-Experten fragen, welcher Compiler hat es falsch gemacht?

PS: gcc-4.8.3, klirrt-3.5.1

+0

PPS: Versuchte es auf [ideone] (http://ideone.com/H9HKPT) mit gcc-4.9.2 - selbe Fehler –

Antwort

16

Soweit ich das sagen kann, im Entwurf C++ Standard Abschnitt 6.8Mehrdeutigkeitslösung bedeckt ist, die sagt, dass es eine Mehrdeutigkeit zwischen und Ausdruck Erklärungen und sagt:

There is an ambiguity in the grammar involving expression-statements and declarations: An expression statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration. [ Note: To disambiguate, the whole statement might have to be examined to determine if it is an expression-statement or a declaration. This disambiguates many examples. [ Example: assuming T is a simple-type-specifier (7.1.6),

und gibt die folgenden Beispiele:

T(a)->m = 7; // expression-statement 
T(a)++; // expression-statement 
T(a,5)<<c; // expression-statement 

T(*d)(int); // declaration 
T(e)[5]; // declaration 
T(f) = { 1, 2 }; // declaration 
T(*g)(double(3)); // declaration 

und sagt dann:

The remaining cases are declarations. [ Example:

class T { 
    // ... 
    public: 
    T(); 
    T(int); 
    T(int, int); 
}; 
T(a); // declaration 
T(*b)(); // declaration 
T(c)=7; // declaration 
T(d),e,f=3; // declaration 
extern int h; 
T(g)(h,2); // declaration 

—end example ] —end note ]

Es scheint, wie dieser Fall fällt in die Erklärung Beispiele insbesondere das letzte Beispiel den Fall, in dem OP zu machen scheint, so gcc dann richtig wäre.

entsprechenden Abschnitt oben 5.2.3Explicit Typkonvertierung (funktionale Notation) erwähnt sagt:

[...] If the type specified is a class type, the class type shall be complete. If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as a prvalue.

und 8.3Bedeutung der Deklaratoren die sagt:

In a declaration T D where D has the form

(D1) 

the type of the contained declarator-id is the same as that of the contained declarator-id in the declaration

T D1 

Parentheses do not alter the type of the embedded declarator-id, but they can alter the binding of complex declarators.

aktualisieren

war ich mit N337 ursprünglich aber wenn wir N4296 Abschnitt aussehen 6.8 wurde ein nun umfasst die folgende Notiz aktualisiert:

If the statement cannot syntactically be a declaration, there is no ambiguity, so this rule does not apply.

was bedeutet, dass gcc da falsch ist: kann

foo x ("bar")("baz"); 

nicht eine gültige Erklärung sein, interpretierte ich ursprünglich Absatz 2 mit der Aussage, wenn Sie Fall beginnt mit einer der folgenden dann ist es Erklärung, die vielleicht ist, wie die gcc Implementierer Int auch erklärt.

I Absatz 2 misstrauischer sein sollte, da den einzigen normativen Teil des Absatzes 2 wirklich nichts gesagt in Bezug auf Absatz 1 und scheint eine Anforderung an einem Beispiel zu setzen, die nicht normativ ist. Wir können sehen, dass diese Aussageform des Paragraphen 2 jetzt tatsächlich eine Notiz ist, die viel mehr Sinn macht.

als T.C. notiert unten, Absatz 2 war eigentlich nie normativ, es erschien nur so und er linked to the change that fixed it.

+0

Danke Shafik.Würde die Erstellung eines temporären 'foo (x)' unter die explizite Typ-Konvertierung von _function-style_ fallen? Ich sollte nicht denken ... –

+0

@InnocentBystander: Nein, ich denke, es ist eine einfache Erklärung. Es wird als 'foo x; analysiert. –

+0

@InnocentBystander fügte weitere Details aus' 5.2.3' hinzu, die das abdecken. –

5

Wenn wir die Linie

std::string x = "foo"; 

dann entfernen g ++ beschwert sich über:

foo(x)("bar")("baz"); 

mit der Syntaxfehler:

foo.cc:20:18: error: expected ',' or ';' before '(' token 
    foo(x)("bar")("baz"); 

Ich sehe nicht, wie foo (x)("bar")("baz"); ein gültiger sein könnte Erklärung, und anscheinend kann g ++ auch nicht. Die Zeile foo x("bar")("baz"); wird mit demselben Fehler zurückgewiesen.

Die in Shafiks Beitrag erwähnte "Ambiguitätsauflösung" tritt nur ein, wenn die Ausdruckanweisung syntaktisch nicht von einer Deklaration zu unterscheiden ist. In diesem Fall handelt es sich jedoch nicht um eine gültige Deklarationssyntax, daher gibt es keine Mehrdeutigkeit, es muss eine Ausdruckanweisung sein.

g ++ kann die Zeile nicht als Ausdruck-Anweisung verarbeiten, daher handelt es sich um einen g ++ - Fehler.

Dies ist unheimlich ähnlich zu this g++ bug kürzlich auf SO diskutiert; es scheint, dass g ++ vielleicht zu früh in der Verarbeitung entscheidet, dass die Zeile eine Deklaration sein muss.