La costruzione della chiamata temporanea in funzione è interpretata come dichiarazione

Ultimamente mi sono imbattuto in un problema che in qualche modo (ma solo in qualche modo) ha senso per me. Si basa sull’interpretazione della costruzione di un temporaneo come dichiarazione del singolo argomento del costruttore (!). Si prega di dare un’occhiata all’esempio minimo qui sotto.

#include  class Foo0{ public: Foo0(int a){}; void doStuff() {std::cout<<"maap"<<std::endl;}; }; class Foo1{ public: Foo1(int a){}; void doStuff() {std::cout<<"maap"<<std::endl;}; }; class Foo2{ public: Foo2(int a){}; void doStuff() {std::cout<<"maap"<<std::endl;}; }; class Bar{ public: Bar(Foo0 foo0, Foo1 foo1, Foo2 foo2){}; }; int main () { int x = 1; Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration 'Foo1 x' previous declaration as 'Foo0 x'; conflicting declaration 'Foo2 x' previous declaration as 'Foo0 x' Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration 'Foo1 x' previous declaration as 'Foo0 x' Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious though. } 

Ho già letto che espressioni come:

 Foo(a); 

Sono interpretati (se esiste un costruttore standard) come dichiarazione di a. Questo ha senso ed è assolutamente soddisfacente, dal momento che puoi semplicemente usare le {} -bracks per rendere esplicita la costruzione. Ma quello che non capisco è:

  1. Perché c’è un problema con la costruzione di bar0? Tutti i Foo non hanno un costruttore standard. Quindi non ha senso interpretare qualcosa come Foo0(x) come dichiarazione di x .

  2. Perché la costruzione di bar1 e bar2 funziona? Per me è ovvio che la costruzione di bar4 funziona, dal momento che utilizzo le {} -brackets per tutti i Foo temporanei, quindi sono esplicito su ciò che voglio.

  3. Se è solo necessario utilizzare le {} -brackets con solo uno dei Foo s per risolvere il problema … perché la costruzione di bar3 fallisce?

  4. Inoltre, x viene dichiarato prima che venga costruita qualsiasi barra. Perché il compilatore non si lamenta di ciò?

L’ultima domanda è relativa alla mia ultima riga di codice di esempio. Per farla breve: cosa pensa il compilatore che voglio che faccia e dove mi manca l’apparenza di shadowing?

PS: Se è interessante, io uso la gcc-4.9.2.
PPS: Ho provato lo stesso con il costruttore della bar prendendo tre Foo0 come argomenti. Stessa storia qui. Ma l’errore non dice nulla sulla dichiarazione in conflitto ma sulla ridefinizione di x .

La regola è che se una dichiarazione ha la syntax di una dichiarazione di funzione, allora è una; altrimenti è una dichiarazione variabile. Esempi sorprendenti di questo sono a volte chiamati parsing più irritanti .

 Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration 'Foo1 x' previous declaration as 'Foo0 x'; conflicting declaration 'Foo2 x' previous declaration as 'Foo0 x' 

Questa è una dichiarazione di funzione: bar0 è il nome, Bar è il tipo di ritorno, ei tipi di parametro sono Foo0 , Foo1 e Foo2 . I nomi dei parametri sono tutti x che è illegale – i nomi dei parametri delle funzioni devono essere diversi. Se cambi x x x a x y z l’errore scompare).

 Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me 

Queste linee e creano oggetti bar1 , bar2 e bar4 di tipo Bar . Non possono essere analizzati come dichiarazioni di funzioni poiché la notazione { } non è una syntax valida in una dichiarazione di funzione.

Pertanto, Foo0{x} ecc. Sono espressioni che forniscono gli argomenti al costruttore di Bar . Foo0{x} e Foo0(x) sono modi equivalenti di dichiarare un temporaneo di tipo Foo0 con l’inizializzatore x .

 Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration 'Foo1 x' previous declaration as 'Foo0 x' 

Penso che questo sia un bug del compilatore; la parte Foo2{x} significa che questa linea non può essere una dichiarazione di funzione; e sembra una dichiarazione valida di una variabile bar3 .

 x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious 

x è un int ; non ha alcun metodo

1) Foo0 (x) viene trattato come un parametro della funzione bar0 in questo caso. Qui, non importa se ha un costruttore standard o no. Non è una dichiarazione e un’inizializzazione di una variabile locale, ma solo una dichiarazione di parametro in una dichiarazione di funzione.

2) La mia ipotesi è che questo abbia qualcosa a che fare con l’analisi, ma qualcuno mi corregge se ho torto .. Esempi bar1 e bar2 funzionano, perché il compilatore sa che bar1 e bar2 sono dichiarazioni di variabili locali (e non dichiarazioni di funzioni) come appena vede la prima occorrenza di {}. Queste prime occorrenze di {} appaiono prima che x sia dichiarato due volte come parametro della funzione.

3) La costruzione di bar3 fallisce, perché il compilatore assume per primo che bar3 è una dichiarazione di funzione. La dichiarazione della funzione prende tre parametri, che sono tutti denominati x. Ovviamente, questo non è corretto.

4) La x nella dichiarazione della funzione è solo un nome per il parametro. È in un ambito diverso rispetto all’intero x che hai dichiarato prima.