Nejvíce otravná analýza - Most vexing parse
![]() | Tento článek je hlavní část nemusí adekvátně shrnout jeho obsah.Říjen 2020) ( |
The nejvíce otravná analýza je specifická forma syntaktické řešení nejednoznačnosti v C ++ programovací jazyk. Termín byl použit Scott Meyers v Efektivní STL (2001).[1] Formálně je to definováno v oddíle 8.2 C ++ jazykový standard.[2]
Příklad s třídami
Příkladem je:
třída Časovač { veřejnost: Časovač();};třída Časoměřič { veřejnost: Časoměřič(konst Časovač& t); int get_time();};int hlavní() { Časoměřič časoměřič(Časovač()); vrátit se časoměřič.get_time();}
Linie
Časoměřič časoměřič(Časovač());
je zdánlivě nejednoznačný, protože jej lze interpretovat buď jako
- A proměnná definice proměnné
časoměřič
třídyČasoměřič
, inicializováno anonymní instancí třídyČasovač
nebo - A deklarace funkce pro funkci
časoměřič
který vrací objekt typuČasoměřič
a má jediný (nepojmenovaný) parametr, který je ukazatelem na funkci vracející objekt typuČasovač
(a bez vstupu). (Vidět Funkční objekt # v C a C ++ )
Většina programátorů očekává první, ale C ++ standard vyžaduje, aby byla interpretována jako druhá.
Například, g ++ dává následující chybovou zprávu:
$ g ++ -c time_keeper.cctime_keeper.cc: Ve funkci ‚int main () ':time_keeper.cc:15: chyba: požadavek na člena „get_time“ v „time_keeper“, což je neklasického typu „TimeKeeper (Timer (*) ())“
Všimněte si, že kompilátor poskytuje chybovou zprávu o příkazu return z hlavní()
: protože interpretovalo prohlášení z časoměřič
jako deklaraci funkce nebudeme moci zavolat členské funkci get_time ()
Na toto.
Clang ++ poskytuje varování:
$ clang ++ time_keeper.cctimekeeper.cc:14:25: Varování: závorky byly disambiguated jako deklarace funkce [-Wvexing-parse] TimeKeeper time_keeper (Timer ()); ^~~~~~~~~timekeeper.cc:14:26: poznámka: přidat dvojici závorek pro deklaraci proměnné TimeKeeper time_keeper (Timer ()); ^ ( )timekeeper.cc:15:21: chyba: základní typ odkazu člena 'TimeKeeper (Timer (*) ())' není a struktura nebo unie návrat time_keeper.get_time (); ~~~~~~~~~~~^~~~~~~~~
Běžné způsoby, jak přinutit kompilátor, aby to považoval za definici proměnné, jsou:
- Přidání další dvojice závorek:
TimeKeeper time_keeper ((Časovač ()));
- Chcete-li použít inicializaci kopírování:[1]
TimeKeeper time_keeper = TimeKeeper (Timer ());
- (V C ++ 11 a později.) Chcete-li použít jednotná inicializace[2][3] se závorkami:
TimeKeeper time_keeper{Časovač ()};
TimeKeeper time_keeper (časovač{});
TimeKeeper time_keeper{Časovač{}};
Příklad s funkcemi
Ještě jednodušší příklad se objeví, když je funkční přetypování určeno k převodu výrazu pro inicializaci proměnné nebo předání parametru konstruktoru
prázdnota F(dvojnásobek zdvojnásobit) { int i(int(zdvojnásobit));}
V tomto případě jsou kulaté závorky zdvojnásobit
jsou nadbytečné a prohlášení o i
je opět deklarace funkce ekvivalentní následujícímu
// vezme celé číslo a vrátí celé čísloint i(int zdvojnásobit);
K disambiguaci ve prospěch deklarace proměnné lze použít stejnou techniku jako v prvním případě výše. Dalším řešením je použít cast cast:
// deklaruje proměnnou nazvanou 'i'int i((int) zdvojnásobit);
Nebo také použít pojmenované obsazení:
// deklaruje proměnnou nazvanou 'i'int i(static_cast<int>(zdvojnásobit));
Jednotná syntaxe inicializace
Používání nového jednotná syntaxe inicializace představený v C ++ 11 řeší tento problém.
Při použití složených závorek je potom problémový kód jednoznačný:
Časoměřič časoměřič{Časovač{}};
Použití složených závorek výše vytvoří definici proměnné pro proměnnou časoměřič
třídy Časoměřič
, inicializováno anonymní instancí třídy Časovač
.
Reference
- ^ Meyers, Scott (2001). Efektivní STL: 50 konkrétních způsobů, jak vylepšit používání standardní knihovny šablon. Addison-Wesley. ISBN 0-201-74962-9.
- ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Programming Languages - C ++ §8.2 Řešení nejednoznačnosti [dcl.ambig.res]
externí odkazy
- Úžasné výkony ClangError Recovery Blog projektu LLVM
- C ++ je "nejvíce otravná analýza" ars technica
- Jednotná inicializační syntax a sémantika