为什么 C++11 强类型枚举不能通过指针转换为基础类型?

2023-12-30

在 C++11 中,我们可以强制转换强类型枚举(enum class) 为其基础类型。但似乎我们不能将指针投射到相同的位置:

enum class MyEnum : int {};

int main()
{
  MyEnum me;

  int iv = static_cast<int>(me); // works
  int* ip = static_cast<int*>(&me); // "invalid static_cast"
}

我试图理解为什么会这样:枚举机制是否有某些东西使得支持这一点变得困难或荒谬?这是标准中的一个简单的疏忽吗?还有别的事吗?

在我看来,如果枚举类型真正构建在如上所述的整型之上,那么我们不仅应该能够转换值,还应该能够转换指针。我们仍然可以使用reinterpret_cast<int*>或 C 型铸件,但那是一把比我想象的更大的锤子。


TL;DR:C++ 的设计者不喜欢类型双关。

其他人指出了为什么标准不允许这样做;我将尝试解释为什么该标准的编写者可能会这样做。根据这个提议 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf,强类型枚举的主要动机是类型安全。不幸的是,类型安全对很多人来说意味着很多事情。可以公平地假设一致性是标准委员会的另一个目标,所以让我们检查一下 C++ 其他相关上下文中的类型安全。

C++ 类型安全

一般来说,在 C++ 中,类型是不相关的,除非明确指定相关(通过继承)。考虑这个例子:

class A
{
    double x;
    int y;
};

class B
{
    double x;
    int y;
};

void foo(A* a)
{
    B* b = static_cast<B*>(a); //error
}

尽管 A 和 B 具有完全相同的表示形式(标准甚至称它们为“标准布局类型”),但如果没有reinterpret_cast。同样,这也是一个错误:

class C
{
public:
    int x;
};

void foo(C* c)
{
    int* intPtr = static_cast<int*>(c); //error
}

尽管我们知道 C 中唯一的东西是 int 并且你可以自由访问它,static_cast失败。为什么?没有明确指定这些类型是相关的。 C++ 旨在支持面向对象编程,它区分了组合和继承。您可以在通过继承相关的类型之间进行转换,但不能在通过组合相关的类型之间进行转换。

根据您所看到的行为,很明显,强类型枚举通过组合与其基础类型相关。为什么标准委员会会选择这个模型?

组合与继承

关于这个问题有很多文章写得比我在这里能写的更好,但我会尝试总结一下。何时使用组合与何时使用继承当然是一个灰色地带,但在这种情况下有很多观点支持组合。

  1. 强类型枚举不适合用作整数值。因此,继承所表示的“is-a”关系并不合适。
  2. 在最高级别上,枚举旨在表示一组离散值。事实上,这是通过为每个值分配一个 id 号来实现的,这一事实通常并不重要(不幸的是,C 公开了并因此强制执行了这种关系)。
  3. 回顾过去提案 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf,列出的允许指定基础类型的原因是指定枚举的大小和符号。这更多的是一个实现细节,而不是枚举的重要部分,再次有利于组合。

在这种情况下,您可能会争论继承或组合是否更好,但最终必须做出决定,并且行为会根据组合进行建模。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 C++11 强类型枚举不能通过指针转换为基础类型? 的相关文章

随机推荐