我一直无法找到是否有在枚举定义中使用关键字的方法,例如:
enum class EServerAction
{
create,
read,
update,
delete
};
在C#中,我可以使用@ char使编译器将其视为标识符。有没有办法在C ++(Visual Studio 2015)中执行此操作?
答案 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_true
或nokw_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 ++标准向前兼容,因为它们可以使用这些关键字添加新语法,这对于引擎盖下的标识符无效。
结束注释
对于int
或char
等其他基本类型,当使用{{1}重新声明时,再也不能使用unsigned long int
或signed char
这些基本类型} / using
。类型typedef
,whar_t
和char16_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 ptr
和tribool
作为枚举来实现true
。 false
- 关键字在这里很重要,因为名称可能与先前定义的名称冲突/使用标识符是不明确的。
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 ++命名空间一样好,但它不允许构造为GL
或using ns::the_class
,但是你不应该使用(全局)。
结束注释
我会选择
using namespace
注意强>
当我写这篇文章时,我试图保留关键字的所有语义;但即使通过将关键字重新定义为宏来触摸关键字也非常糟糕,因为标准禁止它。您可能永远不会知道库/标准库实现/特定系统头如何使用或可能重新定义它们
结束注释