同一枚举类型中,可以用其他枚举器来定义枚举器吗?

21

出于好奇,我正在进行这个实验:

enum RxqType
{
    A = (1 << 0),
    B = (1 << 1),
    C = (A | B),
    D = A+B+C
};

枚举类型C和D是根据早期的枚举类型定义的。这很不寻常,所以我不确定它是否安全。通过谷歌无法找到任何关于它的示例(也许是被忽略了)。

在Visual C++ 2013和MinGW上使用printfcout输出CD时似乎没有问题。但我担心它是否符合标准,并且是否会触发未定义的行为。

有人能回答我对标准符合性和未定义行为的担忧吗?还有其他需要我关注的事情吗?


1
一个来自C++ std的例子:enum { d, e, f=e+2 };... - PiotrNycz
@PiotrNycz 哦,下次提问之前我应该记得查阅相关标准。 - user2486888
@PiotrNycz 严格来说,示例并不具有规范性。尽管标准中包含的示例无疑是符合规范的。 - Lundin
@Lundin,“符合标准”和“好主意”不一定是同一件事情。 ;) (并没有评论这种语法是好还是坏的想法,只是库代码并不总是按照最佳实践编写的。) - Brian S
4个回答

21
enum RxqType
{
    A = (1 << 0),
    B = (1 << 1),
    C = (A | B),
    D = A+B+C
};

在 C 和 C++ 中,这是有效的。

对于 C:

(C11,6.2.1p7) "每个枚举常量的作用域从其定义的枚举器在枚举列表中出现后立即开始。"

对于 C++:

(C++11,3.3.2p4) "枚举器的声明点紧接着其枚举器定义之后。"


5
是的,这在C99标准草案的第6.2.1节“标识符的作用域”中得到了涵盖,告诉我们每个枚举常量在定义后立即进入作用域:
每个枚举常量都有其作用域,该作用域始于其定义枚举项的出现之后。
这在C++标准草案的第3.3.2节“声明点”中得到了涵盖,其中提到:
对于枚举,声明点紧接着其枚举指示符(7.2)或其第一个不透明枚举声明(7.2)中的标识符(如果有)之后。
为了完整起见,我们可以查看C99标准草案的第6.7.2.2节“枚举指示符”,其中告诉我们可以通过常量表达式设置枚举器,并且枚举器本身是一个常量表达式。
enumerator:
    enumeration-constant
    enumeration-constant = constant-expression
6.6常量表达式中涵盖了哪些常量表达式,它告诉我们枚举是常量,并且整数常量的算术表达式也是常量表达式。

1

虽然已经提到,它是完全有效的,但有一件事情你必须注意:当定义枚举类型时,在C++中,已声明的枚举值可能不具有你期望的确切类型。因此,像这样的东西

enum E {
  a = INT_MAX,
  b = UINT_MAX,
  c = a + 1, // error: overflow
};

不是有效的,即使这是有效的:

enum E {
  a = INT_MAX,
  b = UINT_MAX,
};
enum E2 {
  c = a + 1, // okay: a is promoted to unsigned int
};

举个类似的例子,重载决策可能不像你期望的那样工作:

char f(int);
template <typename T>
char (&f(T))[2];

enum E {
  a = 0,
  b = sizeof(f(a)), // 1
};
enum E2 {
  c = sizeof(f(a)), // 2
};

还有其他类似的例子,有些不太直观。

对于C语言来说,规则要简单一些。在C语言中,枚举常量的类型与枚举类型无关,因此即使使用了E2,我的a + 1示例也是无效的。这确保了一致的结果。


-3

是的,100%有效。事实上,这很好,受到赞赏。

enum RxqType
{
    A = (1 << 0),
    B = (1 << 1),
    C = (A | B),
    D = A+B+C
};

3
有人能回答我的担忧吗?关于标准符合性和未定义行为的问题。 - Lundin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接