Подтвердить что ты не робот

Есть ли способ использовать ключевое слово как идентификатор в перечислении?

Я не смог найти, есть ли способ использовать ключевое слово в определении перечисления, например:

enum class EServerAction
{
    create,
    read,
    update,
    delete
};

В С# я могу использовать @ char, чтобы компилятор рассматривал его как идентификатор. Есть ли способ сделать это в С++ (Visual Studio 2015)?

4b9b3361

Ответ 1

Нет, они не могут использоваться.

Из MSDN

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

В правиле для идентификатора указано:

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

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

Ответ 2

Согласно 2.12 [lex.key] в стандарте С++ 14, в качестве идентификаторов должны использоваться некие идентификаторы :

Идентификаторы, показанные в таблице 4, зарезервированы для использования в качестве ключевых слов (то есть они безоговорочно рассматриваются как ключевые слова в фазе 7), за исключением маркера атрибута (7.6.1) [Примечание: ключевое слово export не используется, но зарезервировано для будущего использования. - конец примечания]:

Таблица 4 - Ключевые слова

   alignas continue friend register true
   alignof decltype goto reinterpret_cast try
   asm default if return typedef
   auto delete inline short typeid
   bool do int signed typename
   break double long sizeof union
   case dynamic_cast mutable static unsigned
   catch else namespace static_assert using
   char enum new static_cast virtual
   char16_t explicit noexcept struct void
   char32_t export nullptr switch volatile
   class extern operator template wchar_t
   const false private this while
   constexpr float protected thread_local
   const_cast for public throw

Кроме того, некоторые идентификаторы не должны использоваться:

Кроме того, альтернативные представления, показанные в таблице 5 для некоторых операторов и пунктуаторов (2.6), зарезервированы и не должны использоваться иначе:

Таблица 5 - Альтернативные представления

and and_eq bitand bitor compl not
not_eq or or_eq xor xor_eq

Более того, согласно 2.11 Identifier [lex.name], некоторые из них незаконны для использования, но компилятор не обязан сообщать вам:

некоторые идентификаторы зарезервированы для использования реализацией С++ и стандартными библиотеками (17.6.4.3.2) и не должны использоваться иначе; диагностика не требуется

- Каждое имя, содержащее двойное подчеркивание _ _ или начинающееся с символа подчеркивания, за которым следует заглавная буква (2.12), зарезервировано для реализации для любого использования.

- Каждое имя, начинающееся с символа подчеркивания, зарезервировано для реализации для использования в качестве имени в глобальном пространстве имен.

Ответ 3

В С++ ключевые слова не могут использоваться как идентификаторы, как они могут в С#.

Ответ 4

Это можно сделать с помощью макросов:

#define delete _delete

enum class EServerAction
{
    create,
    read,
    update,
    delete
};

Эта практика обычно обескуражена, потому что теперь вы не можете использовать delete в других частях файла. Но это полезно в некоторых ситуациях, например, при компиляции программы на языке C, которая имеет идентификаторы, называемые ключевыми словами С++ (например, delete), используя компилятор С++.

Это также вызовет путаницу в отладчике, потому что идентификаторы для этих символов не совпадают с идентификаторами, которые находятся в исходном коде.

Ответ 6

РЕДАКТИРОВАТЬ
Краткий ответ: НЕТ!

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

Подумайте об альтернативном способе именования записей enum.
КОНЕЦ РЕДАКТИРОВАНИЯ

НОТА
Я попытался сделать это с помощью C-препроцессора. Следующие примеры кода не являются ни хорошей практикой, ни стандартом. Следующие примеры кода должны демонстрировать только поведение C-препроцессора. Использование этих методов может вызвать проблемы, особенно при использовании библиотечных заголовков, потому что переопределение этих ключевых слов может изменить семантику любого кода.
КОНЕЦ ПРИМЕЧАНИЕ

С некоторыми именами это можно сделать с помощью макросов, здесь все ключевые слова сделаны пригодными для использования в качестве обычных идентификаторов без потери значения самих ключевых слов. Во-первых, сохраняя их в константу или определяя тип с помощью допустимых идентификаторов, таких как nokw_true или nokw_bool. Затем определяем макросы с ключевым словом name для ссылки на псевдонимы.

constexpr static nullptr_t nokw_nullptr = nullptr;
constexpr static bool nokw_true = true;
constexpr static bool nokw_false = false;
using nokw_bool = bool;
using nokw_void = void; // suprising: this can also be used for empty parameter list

#define nullptr nokw_nullptr
#define true nokw_true
#define false nokw_false
#define bool nokw_bool
#define void nokw_void

НОТА
Я протестировал этот код, и он работал так, как будто макросы никогда не были определены. Но нет никакой гарантии, что он ведет себя одинаково на каждом компиляторе C++, потому что это не одно и то же, ключевые слова сильно отличаются от идентификаторов. И он не совместим напрямую с более новыми стандартами C++, потому что они могут добавить новый синтаксис, используя эти ключевые слова, что будет недопустимо с идентификаторами под капотом.
КОНЕЦ ПРИМЕЧАНИЕ

С другими фундаментальными типами, такими как int или char больше невозможно было бы использовать их как unsigned long int или signed char когда они переопределены с using/typedef. Типы whar_t, char16_t и char32_t большую часть времени объявлены typedef и поэтому не являются "реальным" ключевым словом, но если ваш компилятор реализует его непосредственно как ключевое слово, вы можете сделать его using nokw_* = *; использования в качестве идентификатора с using nokw_* = *; подход.
ПРИМЕЧАНИЕ Только не делайте этого! КОНЕЦ ПРИМЕЧАНИЕ

*_cast -keywords также может быть сделан как не -keyword, определяя их в функции:

    template<typename N, typename O>
N nokw_reinterpret_cast(O&& old) { return reinterpret_cast<N>(old); };

#define reinterpret_cast nokw_reinterpret_cast
// other cast-operators follow

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

Но используя определения выше, можно реализовать tribool с ключевыми словами true и false в качестве enum. Здесь важен class -keyword, потому что имена могут конфликтовать с ранее определенными именами/использование идентификаторов неоднозначно.

enum class tribool { true, maybe, false };

Или это также может быть в пространстве имен:

// maybe writing an API for a Visual Basic Application
namespace vb_constants {
    constexpr int true = -1; // in VB True is -1
    constexpr int false = 0;
    // in this namespace the real true and the real false can
    // be accessed through ::true and ::false
};

Записи enum могут быть использованы как tribool::true.

ОДНАКО: Многие программисты используют CAPITALIZED enum-entry-names. Поскольку нет заглавных слов, они всегда будут работать...
НОТА
Это не является нарушением стандарта C++ или стандарта C. По этой же причине часто рекомендуется использовать CAPITALIZED macronames. Макросы видны глобально для всех файлов, включенных после определения, другие объекты могут и должны быть вложены в пространства имен. В противном случае это может привести к конфликту имен. Когда вам нужно определить что-то как макрос, вы должны добавить к макронайму какой-то уникальный текст, например имя вашей библиотеки/приложения, как вы бы назвали пространство имен C++. Это также называлось пространствами имен, прежде чем C++ даже имел пространства имен. Посмотрите на OpenGL, например, все идентификаторы начинаются с GL, это работает так же хорошо, как пространства имен C++, но он не позволяет конструкциям using ns::the_class или using namespace, которое, однако, вы никогда не должны использовать (глобально).
КОНЕЦ ПРИМЕЧАНИЕ

Я бы пошел с

enum class EServerAction {
    CREATE,
    READ,
    UPDATE,
    DELETE
};

НОТА
Когда я писал это, я пытался сохранить всю семантику ключевых слов; но даже трогать ключевые слова, переопределяя их как макросы, очень плохо, потому что это запрещено стандартом. Возможно, вы никогда не узнаете, как библиотеки/стандартные реализации библиотек/конкретные системные заголовки используют или могут их переопределить.
КОНЕЦ ПРИМЕЧАНИЕ