有没有办法在枚举中使用关键字作为标识符?

时间:2016-04-11 11:32:03

标签: c++ enums keyword

我一直无法找到是否有在枚举定义中使用关键字的方法,例如:

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

在C#中,我可以使用@ char使编译器将其视为标识符。有没有办法在C ++(Visual Studio 2015)中执行此操作?

3 个答案:

答案 0 :(得分:3)

根据C ++ 14标准中的2.12 [lex.key],某些标识符绝不能用作标识符:

  

表4中显示的标识符保留用作关键字(即,在第7阶段无条件地将它们视为关键字),但属性标记(7.6.1)除外[注意:导出关键字未使用但保留供将来使用。 - 结束说明]:

     

表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标识符[lex.name],有些非法使用,但编译器无需告诉您:

  

某些标识符保留供C ++实现和标准库(17.6.4.3.2)使用,否则不得使用;无需诊断

     

- 包含双下划线_ _或以下划线后跟大写字母(2.12)开头的每个名称都保留给实现以供任何使用。

     

- 以下划线开头的每个名称都保留给实现,以用作全局命名空间中的名称。

答案 1 :(得分:0)

使用MSVC __标识符https://docs.microsoft.com/en-us/cpp/extensions/identifier-cpp-cli?view=vs-2019

enum class EServerAction
{
    create,
    read,
    update,
    __identifier(delete)
};

答案 2 :(得分:-1)

修改
简答:不!

您只能使用override等上下文关键字作为标识符。但你不应该。该标准仅允许此向后兼容性,可能会被删除或弃用。并且使其适用于每个关键字都意味着打破语言的许多其他语义。

考虑另一种命名枚举条目的方法 结束编辑

注意
我试图通过使用C预处理器来实现它。 以下代码示例既不是良好实践,也不是标准允许的。以下代码示例应仅演示C预处理器的行为。使用这些技术可能会导致问题,尤其是在使用库标题时,因为重新定义这些关键字可能会改变任何代码的语义 结束注释

使用某些名称,可以使用宏执行此操作,这里所有关键字都可用作普通标识符,而不会丢失关键字本身的含义。首先,将它们存储为常量或键入具有有效标识符的类型,例如nokw_truenokw_bool。然后使用keyword-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 ++标准向前兼容,因为它们可以使用这些关键字添加新语法,这对于引擎盖下的标识符无效。
结束注释

对于intchar等其他基本类型,当使用{{1}重新声明时,再也不能使用unsigned long intsigned char这些基本类型} / using。类型typedefwhar_tchar16_t是typedef声明的大部分时间,因此不是" real"关键字,但如果您的编译器直接将其作为关键字实现,则可以使用char32_t方法将其用作标识符。
注意不要这样做! 结束注释

using nokw_* = *; - 关键字也可以通过在函数中定义来作为非关键字:

*_cast

无法定义其他关键字,因为它们既不是类型也不是类似函数的关键字作为强制转换运算符。在您的情况下, 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或删除的功能。

但是,使用上面的定义,可以使用关键字delete ptrtribool作为枚举来实现truefalse - 关键字在这里很重要,因为名称可能与先前定义的名称冲突/使用标识符是不明确的。

class

或者它也可以在命名空间中:

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 }; 一样使用。

但是:许多程序员使用CAPITALIZED枚举输入名称。因为没有大写的关键字,所以这些关键字始终有效... 注意
这不违反C ++标准,也不违反C标准。这也是为什么经常建议使用CAPITALIZED macronames的原因。宏在定义后包含的所有文件全局可见,其他实体可以 嵌套在命名空间中。否则可能导致姓名冲突。当您需要将某些内容定义为宏时,您应该在macroname之前添加一些独特的文本,例如您的库/应用程序名称,就像命名C ++ - 名称空间一样。在C ++甚至具有名称空间之前,这也被称为名称空间。以OpenGL为例,所有标识符都以tribool::true为前缀,这与C ++命名空间一样好,但它不允许构造为GLusing ns::the_class,但是你不应该使用(全局)。
结束注释

我会选择

using namespace

注意
当我写这篇文章时,我试图保留关键字的所有语义;但即使通过将关键字重新定义为宏来触摸关键字也非常糟糕,因为标准禁止它。您可能永远不会知道库/标准库实现/特定系统头如何使用或可能重新定义它们 结束注释