Analiza cea mai supărătoare
Analiza cea mai deranjantă este o formă de rezoluție a ambiguității sintactice C ++ , definită în secțiunea 8.2 din standard. [1] , determinat de faptul că sintaxa pentru inițializarea unei variabile este în unele cazuri ambiguă cu cea a unei declarații de funcție. Termenul cel mai supărător a fost introdus de Scott Meyers în Effective STL (2001). [2]
Exemplu cu clase și obiecte
Următorul este un exemplu de afirmație sau definiție ambiguă:
clasa Timer {
public :
Temporizator ();
};
clasa TimeKeeper {
public :
TimeKeeper ( const Timer & t );
int get_time ();
};
int main () {
TimeKeeper time_keeper ( Timer ());
întoarce-te cu timpul . get_time ();
}
Linia
TimeKeeper time_keeper ( Timer ());
ar putea fi interpretat ca
- definirea unei
time_keeper
variabile aTimeKeeper
clasei, inițializată cu o instanță anonimă aTimer
clasă; - declarația unei funcții
time_keeper
cu tip de returnareTimeKeeper
și un singur parametru (fără nume) de tip pointer pentru a funcționa fără parametri și cu tip de revenireTimer
.
Standardul necesită interpretarea acestei linii în al doilea mod, astfel încât următoarea linie nu va fi validă. De exemplu, g ++ returnează următorul mesaj de eroare:
$ g ++ -c time_keeper.cc
time_keeper.cc: În funcția 'int main ()':
time_keeper.cc:15: eroare: cerere pentru membru 'get_time' în 'time_keeper', care este
de tip non-clasă „TimeKeeper (Timer (*) ())”
deoarece time_keeper
este o funcție declarată pe linia anterioară, deci nu este posibilă apelarea get_time()
pe ea.
Clang ++ oferă un mesaj de avertizare:
$ clang ++ time_keeper.cc timekeeper.cc:14:25: avertisment: parantezele au fost dezambiguate ca declarație de funcție [-Wvexing-parse] TimeKeeper time_keeper (Timer ()); ^ ~~~~~~~~ timekeeper.cc:14:26: notă: adăugați o pereche de paranteze pentru a declara o variabilă TimeKeeper time_keeper (Timer ()); ^ () timekeeper.cc:15:21: eroare: tipul de bază de referință membru „TimeKeeper (Timer (*) ())” nu este structură sau uniune return time_keeper.get_time (); ~~~~~~~~~~~ ^ ~~~~~~~~
Pentru ca declarația să fie interpretată ca o definiție a variabilei inițializată, puteți adăuga o pereche suplimentară de paranteze:
TimeKeeper time_keeper ( ( Timer ()) );
Exemplu cu distribuție funcțională
Un alt exemplu implică utilizarea distribuției funcționale, atunci când este utilizată pentru a converti valoarea unei expresii transmise apoi ca variabilă sau ca parametru la un constructor.
void f ( dublu adouble ) {
int i ( int ( adouble ));
}
În acest caz, i
este interpretat ca o definiție a funcției, echivalentă cu următoarea
// ia un număr întreg și returnează un număr întreg
int i ( int adouble );
Pentru a dezambigua expresia care trebuie interpretată ca o declarație variabilă, puteți utiliza aceeași tehnică ca în exemplul anterior sau puteți înlocui distribuția funcțională cu o distribuție în stil C
// declară o variabilă numită „i”
int i (( int ) adouble );
sau puteți utiliza operatorul de turnare C ++ corespunzător
// declară o variabilă numită „i”
int i ( static_cast < int > ( adouble ));
Sintaxă de inițializare uniformă
Standardul C ++ 11 a introdus sintaxa uniformă de inițializare , care uniformizează sintaxa pentru inițializarea obiectelor sau variabilelor cu cea pentru matrice și permite evitarea oricărei ambiguități cu declarația de funcții. Linia problemă din primul exemplu poate fi rescrisă ca:
TimeKeeper time_keeper { Timer {}};
Notă
- ^ ISO / IEC (2003). ISO / IEC 14882: 2003 (E): Limbaje de programare - C ++ §8.2 Rezoluția ambiguității [dcl.ambig.res]
- ^ Scott Meyers , STL eficient: 50 de moduri specifice de a vă îmbunătăți utilizarea bibliotecii de șabloane standard , Addison-Wesley, 2001, ISBN 0-201-74962-9 .
linkuri externe
- The Most Vexing Parse de Danny Kalev
- Fapte uimitoare ale Clang Error Recovery LLVM Project Blog
- „Analiza cea mai supărătoare” a lui C ++ este tehnică
- Sintaxă și semantică de inițializare uniformă