Il most vexing parse è una forma di soluzione di ambiguità sintattica del C++, definita nella sezione 8.2 dello standardISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §8.2 Ambiguity resolution [dcl.ambig.res], determinata dal fatto che la sintassi per l'inizializzazione di una variabile è in alcuni casi ambigua con quella di dichiarazione di una funzione. La locuzione most vexing parse è stata introdotta da Scott Meyers in Effective STL (2001).

Esempio con classi e oggetti Il seguente è un esempio di dichiarazione o definizione ambigua: class Timer { public: Timer();

class TimeKeeper { public: TimeKeeper(const Timer& t);

int get_time();

int main() { TimeKeeper time_keeper(Timer()); return time_keeper.get_time(); }

La riga TimeKeeper time_keeper(Timer()); potrebbe essere interpretata come la definizione di una variabile di classe , inizializzata con un'istanza anonima della classe ; la dichiarazione di una funzione con tipo di ritorno e un singolo parametro (senza nome) di tipo puntatore a funzione senza parametri e con tipo di ritorno .

Lo standard richiede di interpretare questa riga nella seconda maniera, per cui la riga successiva non sarà valida. Ad esempio, g++ restituisce il seguente messaggio di errore: $ g++ -c time_keeper.cc time_keeper.cc: In function ‘int main()’: time_keeper.cc:15: error: request for member ‘get_time’ in ‘time_keeper’, which is of non-class type ‘TimeKeeper(Timer (*)())’ in quanto è una funzione dichiarata alla riga precedente, per cui non è possibile chiamare su essa il metodo .

Clang++ fornisce un messaggio di warning: $ clang++ time_keeper.cc timekeeper.cc:14:25: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse] TimeKeeper time_keeper(Timer()); ^~~~~~~~~ timekeeper.cc:14:26: note: add a pair of parentheses to declare a variable TimeKeeper time_keeper(Timer()); ^ ( ) timekeeper.cc:15:21: error: member reference base type 'TimeKeeper (Timer (*)())' is not a structure or union return time_keeper.get_time(); ~~~~~~~~~~~^~~~~~~~~

Per fare in modo che l'istruzione venga interpretata come definizione di variabile con inizializzazione, è possibile aggiungere una coppia di parentesi supplementare: TimeKeeper time_keeper( (Timer()) );

Esempio con cast funzionale Un altro esempio coinvolge l'uso del cast funzionale, quando viene usato per convertire il valore di un'espressione passata poi come variabile o come parametro di un costruttore

void f(double adouble) { int i(int(adouble)); }

In questo caso, viene interpretata come una definizione di funzione, equivalente alla seguente

// takes an integer and returns an integer int i(int adouble);

Per disambiguare l'espressione affinché venga interpretata come dichiarazione di variabile, si può usare la stessa tecnica dell'esempio precedente, oppure si può sostituire il cast funzionale con un cast in stile C

// declares a variable called 'i' int i((int) adouble);

oppure si può usare l'opportuno operatore di casting del C++

// declares a variable called 'i' int i(static_cast<int>(adouble));

Uniform initialization syntax

Lo standard C++11 ha introdotto la uniform initialization syntax (sintassi di inizializzazione uniforme), che uniforma la sintassi per l'inizializzazione di oggetti o variabili con quella per gli array e permette di evitare ogni ambiguità con la dichiarazione di funzioni. La riga problematica del primo esempio può essere riscritta come:

TimeKeeper time_keeper{Timer{}};

Note

Collegamenti esterni The Most Vexing Parse by Danny Kalev Amazing feats of Clang Error Recovery LLVM Project Blog C++'s "most vexing parse" ars technica

Categoria:C++