【问题标题】:C++11 Enum forward causes "underlying type mismatch"C++11 Enum forward 导致“基础类型不匹配”
【发布时间】:2017-08-03 15:48:07
【问题描述】:

我正在使用 C++11 并包含一个用 C++03 实现的 h 文件。在我包含的 h 文件中,定义了一个枚举 Foo。我想在code.h 中声明一个转发并在code.cpp 中使用它:

header.h:

enum Foo {A=1};

code.h:

enum Foo : int; // also tried : unsigned int, long, short, unsigned short, char, unsigned char
void bar(Foo foo);

code.cpp:

#include header.h
void bar(Foo foo) { }

这是我编译时遇到的错误(测试g++ 4.8.5和g++ 5.3.1):

In file included from code.cpp:2:0:
header.h:1:6: error: underlying type mismatch in enum ‘enum Foo’
 enum Foo {A=1};
      ^
In file included from code.cpp:1:0:
code.h:3:12: error: previous definition here
 enum Foo : int;

如果我将 header.h 更改为:

enum Foo : int {A=1};

但我不拥有该标题,也无法更改它。从表面上看错误,听起来我只需要知道 g++ 用于未指定底层类型的枚举的类型,然后在我的转发中使用该类型。

Even this simple example doesn't work

#include <iostream>
#include <string>
#include <type_traits>

enum Foo {A=1};
enum Foo : unsigned; // : std::underlying_type<Foo>::type also doesn't work

int main()
{

  std::cout << "Hello, world\n";
}

【问题讨论】:

  • 好吧,C++ 标准明确禁止这样做(前向声明枚举需要固定的底层类型)。也许另一种解决方案是可能的,比如将枚举包装在一个结构中?
  • 阅读 stackoverflow.com/questions/71416/…,我认为在 C++11 中是可能的。
  • 从 C++11 开始,您可以前向声明一个枚举,但这需要修复底层类型(“指定一个枚举基数”),并为每个声明重复相同的底层类型(前向-声明或实际声明)。因此,如果您不能将基础类型添加到外部标头,那么您不能(不允许)前向声明此枚举。
  • std::underlying_type 告诉您enum 的基础类型。它对您的枚举有什么影响?
  • @Yakk,unsigned。但是,如果我这样做 enum Foo : unsigned - 我会收到上面的错误。

标签: c++ c++11 gcc g++ forward-declaration


【解决方案1】:

似乎没有任何方法可以做到这一点,即使您指定了与编译器为您的 C++03 风格 enum 选择的完全相同的基础类型

示例:编译以下代码...

enum Foo { A=1 };
cout << typeid(typename std::underlying_type<Foo>::type).name();

...on Coliru and demangling via c++filt 将使用 g++clang++ 打印 "unsigned int"

即使您将unsigned int 指定为Foo 前向声明 的显式基础类型both compilers will complain

enum Foo : unsigned int;
void bar(Foo);

enum Foo {A=1};

main.cpp:8:6: error: enumeration previously declared with fixed underlying type
enum Foo {A=1};
     ^
main.cpp:5:6: note: previous declaration is here
enum Foo : unsigned int;
     ^

这是因为 前向声明 和“真实”enum 声明都需要具有相同的显式基础类型,即使您设法“猜测”编译器会为你选择什么。


tl;dr:如果前向声明和真实声明具有相同的显式指定基础类型,您只能前向声明enum

【讨论】:

  • 顺便说一下,VisualStudio(不记得是哪个版本)接受了底层类型规范之间的不匹配(作为扩展)。这会导致危险的不匹配,其中枚举的大小在同一个翻译单元内是不同的,甚至是不正确的代码。我认为强制枚举声明之间关于底层类型规范的一致性是个好主意。
  • 在 g++ (7.4) 上面示例代码中的 cout 行无法编译。应该是std::underlying_type&lt;Foo&gt;::type 而不是std::underlying_type_t&lt;Foo&gt;::type
【解决方案2】:

如果你在前向声明中给它一个固定的底层类型,你只能前向声明一个枚举。另外,枚举的定义必须使用相同固定的底层类型。

您的问题是header.h 中的枚举定义没有基础类型,但后面的前向声明有一个。他们必须有一个。

【讨论】:

  • 我开始明白这行不通,但我看不出有什么理由不这样做。至少这应该是可能的:enum Foo : std::underlying_type&lt;Foo&gt;::type。我的意思是总有一个底层类型,只是在 C++03 风格中它是隐式的。
  • @ytoledano:您要求编译器确定尚未定义的枚举的隐式底层类型。那是不可能。编译器没有看到Foo 的定义,因此std::underlying_type&lt;Foo&gt;::type 不是合法的语法。隐式底层类型基于Foo 的定义,它位于您未包含的标头中(如果包含,则没有必要向前声明枚举)。
【解决方案3】:

在我今天的 gcc 版本中,您必须定义两次确切的类型,不仅在前向 声明中,而且在 定义中:

enum Foo : int;

...

enum Foo : int {A=1};

这对我有用,编译器是 gcc 7.3.0。

【讨论】:

    猜你喜欢
    • 2021-07-30
    • 1970-01-01
    • 2015-04-30
    • 2016-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    相关资源
    最近更新 更多