Самый досадный разбор - Most vexing parse

В самый досадный разбор это особая форма синтаксического разрешение неоднозначности в 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(Таймер());

кажется неоднозначным, поскольку его можно интерпретировать либо как

  1. а Переменная определение переменной time_keeper класса TimeKeeper, инициализированный анонимным экземпляром класса Таймер или же
  2. а объявление функции для функции 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, инициализированный анонимным экземпляром класса Таймер.

Рекомендации

  1. ^ Мейерс, Скотт (2001). Эффективный STL: 50 конкретных способов улучшить использование стандартной библиотеки шаблонов. Эддисон-Уэсли. ISBN  0-201-74962-9.
  2. ^ ISO /IEC (2003). ISO / IEC 14882: 2003 (E): Языки программирования - C ++ §8.2 Разрешение неоднозначности [dcl.ambig.res]

внешняя ссылка