Ukážeme si dva případy, kdy přítomnost kulatých závorek v C++ na první pohled působí zbytečně, ale přitom má značný vliv na význam kódu. A nebojte, nebude se jednat o uzávorkování z důvodů priority operátorů :).
První případ
Mějme následující definici proměnné v
typu std::vector<int>
:
std::vector<int> v((std::vector<int>()));
Pokud bychom závorky odstranili
std::vector<int> v(std::vector<int>());
tak překvapivě nedostaneme definici proměnné typu std::vector<int>
, ale deklaraci funkce v
, která vrací std::vector<int>
a jako parametr má ukazatel na funkci, která nepřebírá žádné parametry a vrací std::vector<int>
. Důvodem je pravidlo v C++ říkající, že cokoliv co může být chápáno jako deklarace má být chápáno jako deklarace.
Jinou možností je buď použití uniformní inicializace z C++11:
std::vector<int> v{std::vector<int>()};
nebo prosté vynechání inicializátoru:
std::vector<int> v;
jež má v tomto případě stejný efekt: vytvoření prázdného vektoru v
.
Druhý případ
O případu výše už jste pravděpodobně slyšeli. Druhý případ bude zajímavější. Někteří programátoři mají zvyk při psaní return
ozávorkovávat návratovou hodnotu:
return (a + 5);
Ona přítomnost nadbytečných závorek nám však překvapivě může uškodit. Mějme následující dvě funkce:
decltype(auto) foo1() { auto result = bar(); return result; } decltype(auto) foo2() { auto result = bar(); return (result); }
Používáme zde decltype(auto)
a automatickou dedukci návratového typu funkce z C++14.
Člověk by čekal, že obě funkce budou ekvivalentní. Přeci jen, ve foo2
jsou akorát "nadbytečné závorky". Opak je však pravdou. Zatímco první funkce vrací výsledek hodnotou, ta druhá vrací referenci na lokální proměnnou result
... Pokud se pak někdo pokusí modifikovat návratovou hodnotu z foo2()
, čeká ho jízda do země nedefinovaného chování, která v nejlepším případě skončí segfaultem (přístup na neplatnou paměť, v tomto případě do stack framu funkce po jejím návratu).
Příčinou je fungování decltype
, který je citlivý na přítomnost závorek [C++14, 7.1.6.2, §4]:
int i; decltype(i) // int decltype((i)) // int &
Je proto třeba si na přítomnost závorek v souvislosti s decltype
dávat pozor.