2015-02-02 15 views
25

Qualcuno ha avuto l'asked l'altro giorno perché qualcosa compila con clang, ma non con gcc. Ho capito intuitivamente cosa stava succedendo e sono stato in grado di aiutare la persona, ma mi sono chiesto: secondo lo standard, quale compilatore era corretto? Ecco una versione bollito giù del codice:g ++ rifiuta, clang ++ accetta: 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; 
} 

Questo compila bene con clangore ++, ma g ++ dà il seguente errore:

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"; 

Se aggiungo un paio di parentesi in linea 21, g ++ è felice:

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

In altre parole, g ++ interpreta questa linea come:

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

È un bug in g ++, ma di nuovo, volevo chiedere agli esperti standard, quale compilatore ha sbagliato?

PS: gcc-4.8.3, clang-3.5.1

+0

PPS: provato su [ideone] (http://ideone.com/H9HKPT) con gcc-4.9.2 - stesso errore –

risposta

16

Per quanto posso dire questo è coperto nel progetto di C++ sezione standard 6.8ambiguità risoluzione che dice che non ci può essere un'ambiguità tra le espressioni e le dichiarazioni e dice:

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),

e dà i seguenti esempi:

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 

e poi dice:

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 ]

Sembra che questo caso cade nelle esempi di dichiarazione in particolare nell'ultimo esempio sembra fare il caso nel PO, così gcc sarebbe corretto allora.

sezione Rilevante menzionato sopra 5.2.3conversione di tipo esplicita (notazione funzionale) dice:

[...] 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.

e 8.3Significato dichiaratori che dice:

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.

Aggiorna

Mi è stato originariamente usando N337 ma se guardiamo N4296 sezione 6.8 è stato aggiornato l'ora comprende la seguente nota:

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

il che significa che gcc non è corretto in quanto:

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

non può essere una dichiarazione valida, ho interpretato originariamente il paragrafo 2 come se il tuo caso iniziasse con una delle seguenti affermazioni, allora è la dichiarazione, che è forse il modo in cui l'implementatore gcc int anche trasgredito.

avrei dovuto essere più sospettoso del paragrafo 2 in quanto l'unica parte normativa del paragrafo 2 davvero non disse nulla riguardo al paragrafo 1 e sembra mettere un requisito di un esempio che non è normativo. Possiamo vedere che il paragrafo 2 del modulo di dichiarazione è in realtà una nota che ha molto più senso.

Come T.C. annotato sotto, il paragrafo 2 in realtà non è mai stato normativo, è appena apparso in quel modo e lui linked to the change that fixed it.

+0

Grazie Shafik.La creazione temporanea di 'foo (x)' rientra in _function-style tipo esplicito conversion_? Non dovrei pensare così ... –

+0

@InnocentBystander: No, penso che sia una semplice dichiarazione. Viene analizzato come 'foo x;' –

+0

@InnocentBystander ha aggiunto ulteriori dettagli da '5.2.3' che lo copre. –

5

Se togliamo la linea

std::string x = "foo"; 

allora g ++ lamenta:

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

con l'errore di sintassi:

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

non vedo come foo (x)("bar")("baz"); potrebbe essere una valida dichiarazione, e apparentemente g ++ non può neanche. La riga foo x("bar")("baz"); viene rifiutata con lo stesso errore.

La "risoluzione di ambiguità" menzionata nel post di Shafik viene attivata solo quando l'espressione-espressione è sintatticamente indistinguibile da una dichiarazione. Tuttavia in questo caso non è una sintassi di dichiarazione valida, quindi non c'è ambiguità, deve essere una dichiarazione di espressione.

g ++ non riesce a elaborare la riga come un'espressione-espressione quindi è un bug g ++.

Questo è stranamente simile a this g++ bug recentemente discusso in SO; sembra che g ++ stia forse decidendo troppo presto nell'elaborazione che la linea deve essere una dichiarazione.