Почему вместо зарезервированных ключевых слов используются переопределенные и конечные идентификаторы со специальным значением?

Добавлены оба параметра переопределить спецификатор и окончательный спецификатор в С++ 11. Они отличаются от других спецификаторов, добавленных в С++ 11, таких как constexpr и decltype, поскольку они не являются ключевыми словами и поэтому доступны для использования в качестве идентификаторов:

int main()
{
  int override = 0 ;    // Ok
  int final = 0 ;       // Ok
  //int constexpr = 0 ; // Error
}

Они называются идентификаторами со специальным значением, которые описаны в стандартном разделе проекта С++ 11 2.11 [lex.name] (выделено мной):

Идентификаторы в таблице 3 имеют особое значение при появлении в определенном контексте. Когда упоминается в грамматике, эти идентификаторы используются явно, а не используют идентификатор грамматическое производство. любая двусмысленность относительно того, имеет ли данный идентификатор особое значение разрешено интерпретировать токен как регулярный Идентификатор.

и Таблица 3 - Идентификаторы со списками специальных значений как переопределяющие, так и окончательные.

Почему эти два спецификатора оказались идентификаторами со специальным значением вместо ключевых слов?

Ответ 1

Добавление новых ключевых слов затруднено, поскольку оно отнимает у пользователя идентификаторы. В результате он становится компромиссом между выбором идентификаторов, которые потенциально могут разрушить старый код в настоящее время с использованием идентификатора или выбора наименований, которые вряд ли могут сломать старый код, но уродливы или не имеют смысла в том, как они используются.

В этом конкретном случае переопределение и окончательное окончание используются в грамматике в тех местах, где не могут появляться идентификаторы пользователя. Поэтому в этих местах идентификаторы могут иметь особое значение, и за пределами этих контекстов их можно рассматривать как обычный идентификатор, оставляя идентификаторы доступными для пользователей. C++/CLI использовал эту технику с 2005, и они называются контекстно-зависимыми ключевыми словами, которые описаны в стандарте С++/CLI < > . Идентификаторы.

Мы можем видеть в записи, в которой рассматриваются компромиссы различных методов добавления поддержки атрибутов виртуального управления в N3163: переопределение управления с использованием контекстных ключевых слов, В нем обсуждались три варианта:

  • Использование [[attributes]], которое было сочтено нежелательным по причинам, в том числе, это просто маскирующие ключевые слова (измененный пример из статьи ниже):

    class A : public B {
      virtual void f [[override]] () { ... }
      virtual void h [[final]] () { ... }
    };
    
  • Используйте зарезервированные ключевые слова, которые потенциально могут нарушить существующий код, если не выбраны уродливые имена (измененный пример из статьи ниже):

    class A : public B {
      virtual void f override_func () { ... }
      virtual void h final_func () { ... }
    };
    
  • Использовать контекстно-зависимые ключевые слова, которые не нарушают существующий код, допускают красивые имена (измененный пример из бумаги ниже):

    class A : public B {
      virtual void f() override { ... }
      virtual void h() final { ... }
    };
    

В следующем абзаце из статьи суммируется аргумент использования контекстно-зависимых ключевых слов по двум другим вариантам (акцент мой):

В Rapperswil наблюдалось, что этот подход может сделать исправление ошибок и подсветка синтаксиса сложнее. Например, подсветка синтаксиса немного сложнее, потому что вместо глобального выделив ключевое слово, которое вам нужно для синтаксического анализа, чтобы узнать, идентификатор находится в том месте, где он имеет особое значение, и должен быть выделены. Но это не исключительно сложно, особенно не по сравнению с другими гораздо более сложными вещами, которые мы уже имеем делать в С++ по сравнению с другими языками.

Это незначительные неудобства для нескольких авторов компилятора в течение недели, но для пользователей. Это правильный компромисс. В противном случае, с уродливыми глобально зарезервированными именами (Вариант 2) или неуместными и видимый болт - по атрибутам (вариант 1) упрощает работу нескольких авторов компилятора в течение недели, но это могут быть миллионы пользователей с вечно.

Изменения были применены к стандарту через N3206: Управление переопределением: Устранение атрибутов и N3272: последующие действия по переопределению управление.