Самый досадный разбор - Most vexing parse
Эта статья ведущий раздел не может адекватно подвести итог его содержание.Октябрь 2020) ( |
В самый досадный разбор это особая форма синтаксического разрешение неоднозначности в C ++ язык программирования. Термин использовался Скотт Мейерс в Эффективный STL (2001).[1] Формально это определено в разделе 8.2. Стандарт языка C ++.[2]
Пример с классами
Пример:
учебный класс Таймер { общественный: Таймер();};учебный класс TimeKeeper { общественный: TimeKeeper(const Таймер& т); int get_time();};int главный() { TimeKeeper time_keeper(Таймер()); возвращаться time_keeper.get_time();}
Линия
TimeKeeper time_keeper(Таймер());
кажется неоднозначным, поскольку его можно интерпретировать либо как
- а Переменная определение переменной
time_keeper
классаTimeKeeper
, инициализированный анонимным экземпляром классаТаймер
или же - а объявление функции для функции
time_keeper
который возвращает объект типаTimeKeeper
и имеет единственный (безымянный) параметр, который является указателем на функцию, возвращающую объект типаТаймер
(и ничего не предпринимает). (Видеть Функциональный объект # в C и C ++ )
Большинство программистов ожидают первого, но Стандарт C ++ требует, чтобы его интерпретировали как второе.
Например, g ++ дает следующее сообщение об ошибке:
$ g ++ -c time_keeper.cctime_keeper.cc: В функции int main ():time_keeper.cc:15: ошибка: запрос члена «get_time» в «time_keeper», который неклассового типа «TimeKeeper (Timer (*) ())»
Обратите внимание, что компилятор выдает сообщение об ошибке, касающееся оператора возврата главный()
: поскольку он интерпретировал объявление time_keeper
в качестве объявления функции мы не сможем вызвать функцию-член get_time ()
на этом.
Clang ++ дает предупреждение:
$ clang ++ time_keeper.cctimekeeper.cc:14:25: предупреждение: круглые скобки были исключены как объявление функции [-Wvexing-parse] TimeKeeper time_keeper (Таймер ()); ^~~~~~~~~timekeeper.cc:14:26: примечание: добавьте пару круглых скобок для объявления переменной TimeKeeper time_keeper (Timer ()); ^ ( )timekeeper.cc:15:21: ошибка: ссылочный базовый тип TimeKeeper (Timer (*) ()) не является структура или союз вернуть time_keeper.get_time (); ~~~~~~~~~~~^~~~~~~~~
Распространенные способы заставить компилятор рассматривать это как определение переменной:
- Чтобы добавить дополнительную пару круглых скобок:
TimeKeeper time_keeper ((Таймер ()));
- Чтобы использовать инициализацию копии:[1]
TimeKeeper time_keeper = TimeKeeper (Таймер ());
- (В C ++ 11 и позже.) Для использования единообразная инициализация[2][3] с подтяжками:
TimeKeeper time_keeper{Таймер ()};
TimeKeeper time_keeper (Таймер{});
TimeKeeper time_keeper{Таймер{}};
Пример с функциями
Еще более простой пример появляется, когда функциональное приведение предназначено для преобразования выражения для инициализации переменной или передачи в параметр конструктора.
пустота ж(двойной двойной) { int я(int(двойной));}
В этом случае круглые скобки вокруг двойной
излишни, и объявление я
снова является объявлением функции, эквивалентным следующему
// принимает целое число и возвращает целое числоint я(int двойной);
Чтобы устранить неоднозначность в пользу объявления переменной, можно использовать тот же метод, что и для первого случая выше. Другое решение - использовать обозначение приведения:
// объявляет переменную с именем 'i'int я((int) двойной);
Или также использовать именованное приведение:
// объявляет переменную с именем 'i'int я(static_cast<int>(двойной));
Единый синтаксис инициализации
Используя новый единый синтаксис инициализации представленный в C ++ 11 решает эту проблему.
Таким образом, проблемный код становится однозначным при использовании фигурных скобок:
TimeKeeper time_keeper{Таймер{}};
Использование фигурных скобок, как указано выше, создает определение переменной для переменной time_keeper
класса TimeKeeper
, инициализированный анонимным экземпляром класса Таймер
.
Рекомендации
- ^ Мейерс, Скотт (2001). Эффективный STL: 50 конкретных способов улучшить использование стандартной библиотеки шаблонов. Эддисон-Уэсли. ISBN 0-201-74962-9.
- ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §8.2 Разрешение неоднозначности [dcl.ambig.res]