Jump to content

Самый неприятный разбор

Самый неприятный синтаксический анализ — это нелогичная форма разрешения синтаксической неоднозначности в языке программирования C++ . В определенных ситуациях грамматика C++ не может отличить создание объекта параметра от указания типа функции . В таких ситуациях компилятор должен интерпретировать строку как спецификацию типа функции.

возникновение

[ редактировать ]

Термин «самый неприятный анализ» впервые был использован Скоттом Мейерсом в его книге «Эффективный STL» 2001 года . [1] Хотя это явление необычно для C , оно было довольно распространено в C++ до появления единообразной инициализации в C++11 . [2]

Приведения в стиле C

[ редактировать ]

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

void f(double my_dbl) {
  int i(int(my_dbl));
}

Строка 2 выше неоднозначна. Одна из возможных интерпретаций — объявить переменную i с начальным значением, полученным путем преобразования my_dbl к int. Однако C допускает использование лишних круглых скобок вокруг параметров функции объявлений ; в этом случае декларация i вместо этого является объявлением функции, эквивалентным следующему:

// A function named i takes an integer and returns an integer.
int i(int my_dbl);

Безымянный временный

[ редактировать ]

Более подробный пример:

struct Timer {};

struct TimeKeeper {
  explicit TimeKeeper(Timer t);
  int get_time();
};

int main() {
  TimeKeeper time_keeper(Timer());
  return time_keeper.get_time();
}

Линия

  TimeKeeper time_keeper(Timer());

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

  1. определение переменной для переменной time_keeper класса TimeKeeper, инициализированный анонимным экземпляром класса Timer или
  2. для объявление функции функции time_keeper который возвращает объект типа TimeKeeper и имеет один (безымянный) параметр, тип которого является функцией (указатель на) [Примечание 1] не принимать никаких данных и возвращать Timer объекты.

Стандарт C++ требует второй интерпретации, которая несовместима с последующей строкой 10 выше. Например, Clang++ предупреждает, что самый неприятный анализ был применен в строке 9 и ошибки в последующей строке 10: [3]

$ clang++ time_keeper.cc
timekeeper.cc:9:25: warning: parentheses were disambiguated as a function declaration
      [-Wvexing-parse]
  TimeKeeper time_keeper(Timer());
                        ^~~~~~~~~
timekeeper.cc:9:26: note: add a pair of parentheses to declare a variable
  TimeKeeper time_keeper(Timer());
                         ^
                         (      )
timekeeper.cc:10:21: error: member reference base type 'TimeKeeper (Timer (*)())' is not a
      structure or union
  return time_keeper.get_time();
         ~~~~~~~~~~~^~~~~~~~~

Требуемая интерпретация этих двусмысленных заявлений редко соответствует действительности. [4] [5] Типы функций в C++ обычно скрыты за определениями типов и обычно имеют явную ссылку или квалификатор указателя . Чтобы обеспечить альтернативную интерпретацию, типичным методом является другой синтаксис создания или преобразования объектов.

В примере преобразования типов для приведения доступны два альтернативных синтаксиса: «приведение в стиле C».

// declares a variable of type int
int i((int)my_dbl);

или именованный состав:

int i(static_cast<int>(my_dbl));

В примере объявления переменной предпочтительным методом (начиная с C++11) является унифицированная инициализация (фигурные скобки). [6] Это также позволяет ограниченно полностью опускать имя типа:

//Any of the following work:
TimeKeeper time_keeper(Timer{});
TimeKeeper time_keeper{Timer()};
TimeKeeper time_keeper{Timer{}};
TimeKeeper time_keeper(     {});
TimeKeeper time_keeper{     {}};

До C++11 распространенными методами принудительной интерпретации было использование дополнительных круглых скобок или инициализация копирования: [5]

TimeKeeper time_keeper( /*Avoid MVP*/ (Timer()) );
TimeKeeper time_keeper = TimeKeeper(Timer());

В последнем синтаксисе инициализация копирования , скорее всего, будет оптимизирована компилятором. [7] Начиная с C++17 эта оптимизация гарантирована. [8]

Примечания

[ редактировать ]
  1. ^ Согласно правилам распада типов C++, объект функции, объявленный как параметр, эквивалентен указателю на функцию этого типа. См. Функциональный объект#В C и C++ .
  1. ^ Мейерс, Скотт (2001). Эффективный STL: 50 конкретных способов улучшить использование стандартной библиотеки шаблонов . Аддисон-Уэсли. ISBN  0-201-74962-9 .
  2. ^ Гроб, Джерри (29 декабря 2012 г.). «С++ — какова цель самого неприятного синтаксического анализа?» . Переполнение стека . Архивировано из оригинала 17 января 2021 года . Проверено 17 января 2021 г.
  3. ^ Латтнер, Крис (5 апреля 2010 г.). «Удивительные возможности восстановления ошибок Clang» . Блог проекта LLVM . Самый неприятный разбор. Архивировано из оригинала 26 сентября 2020 года . Проверено 17 января 2021 г.
  4. ^ ДокторПицца; Прототипированный; ВБ; эвзека; Симпсон, Гомер Дж. (октябрь 2002 г.). «Самый неприятный синтаксический анализ C++ » . Открытый форум АрсТехника . Архивировано из оригинала 20 мая 2015 года . Проверено 17 января 2021 г.
  5. ^ Jump up to: а б Боккара, Джонатан (30 января 2018 г.). «Самый неприятный анализ: как его обнаружить и быстро исправить» . Свободное владение С++ . Архивировано из оригинала 25 ноября 2021 г. Проверено 17 января 2021 г.
  6. ^ Страуструп, Бьярне (19 августа 2016 г.). «Часто задаваемые вопросы по C++11» . www.stroustrup.com . Единый синтаксис и семантика инициализации. Архивировано из оригинала 20 августа 2021 г. Проверено 17 января 2021 г.
  7. ^ «Мифы и городские легенды о C++» . Часто задаваемые вопросы по C++ . Что такое копирование? Что такое РВО?. Архивировано из оригинала 17 января 2021 года . Проверено 17 января 2021 г.
  8. ^ Девлигер, Йонас (21 ноября 2016 г.). «Гарантированное исключение копирования» . Йонас Девлигер . Архивировано из оригинала 25 ноября 2021 г. Проверено 17 января 2021 г. Однако обратите внимание на предостережения, описанные в Бренд, C++ (11 декабря 2018 г.). «Гарантированное удаление копий не приводит к удалению копий» . Блог группы Microsoft C++ . Архивировано из оригинала 25 ноября 2021 г. Проверено 17 января 2021 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: d551e2d7d33e63168fd9e51cf276b660__1717677420
URL1:https://arc.ask3.ru/arc/aa/d5/60/d551e2d7d33e63168fd9e51cf276b660.html
Заголовок, (Title) документа по адресу, URL1:
Most vexing parse - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)