【问题标题】:Why unscoped enums' declaration compiles?为什么无范围枚举的声明编译?
【发布时间】:2017-09-23 12:28:26
【问题描述】:

在 Scott Meyers 的 Effective Modern C++ 书中提到,非作用域枚举和作用域枚举(枚举类)之间的主要区别之一是我们不能转发声明前者(参见第 3 章,第 10 项 - “更喜欢有范围的枚举而不是无范围的枚举”)。例如:

enum Color;            *// error!*
enum class Color;      *// fine*

但是我写了下面提到的小例子,发现不是这样。

test.h

#pragma once
enum names;
void print(names n);

test.cpp

#include "test.h"

#include <iostream>

enum names { John, Bob, David };

void print(names n)
{
    switch (n)
    {
    case John:
    case Bob:
    case David:
        std::cout << "First names." << std::endl;
        break;
    default:
        std::cout << "Other things" << std::endl;
    };
}

ma​​in.cpp

#include "test.h"
#include <iostream>

int main()
{
    names n = static_cast<names>(2);
    print(n);
    return 0;
}

我使用过 VC14 编译器 (Visual Studio 2015)。这是编译器的错误或功能吗?还有什么?如果这是错误或功能(考虑到 Meyers 说这是无作用域枚举和作用域枚举之间的主要区别),则意味着编译器能够管理我们可以声明无作用域枚举的情况。因此,是否需要在枚举之后添加一个新关键字class?当然,有人会说作用域枚举还有另外两个特点。据我了解,上述功能是最重要的。

【问题讨论】:

  • 这在 Visual Studio 2017 中无法编译 - 所以听起来它要么是编译器错误,要么是编译器特定的扩展
  • 这是 MSVC 编译器的一个缺陷。它甚至可以使用/permissive- 成功编译,这会强制 MSVC 进入一致性模式。
  • @UnholySheep 您使用的是什么 MSVC 版本?对我来说,它在 19.11.25508.2 和 19.11.25545 上都使用 /permissive- 成功编译。
  • @tambre 我正在使用 MSVC 19.11.25506,即使没有 /permissive-,我也会收到错误“C3432 'names':无作用域枚举的前向声明必须具有基础类型”
  • @tambre 我尝试升级到 MSVC 19.11.25508.2,但我仍然收到与以前相同的错误 - 编辑:我的项目在设置中有 /Za(禁用语言扩展) - 删除它确实允许这样做编译代码

标签: c++ c++11 enums


【解决方案1】:

C++11

首先:C++11 确实允许无范围枚举的前向声明。您只需将底层类型提供给编译器(来自 Effective Modern C++,第 3 章,第 10 项的示例):

enum Color: std::uint8_t;

您使用的是编译器的非标准扩展,但无论如何都有可能。

重要与否

Scott Meyers 在引用的章节中说:

似乎作用域枚举比非作用域枚举具有第三个优势 枚举,因为作用域枚举可能是前向声明的,即它们的名称 可以在不指定其枚举数的情况下声明: [...] 在 C++11,无作用域的枚举也可以前向声明,但只能在 一些额外的工作。

“似乎”的意思是“是”的反义词。 Scott Meyers 本人表示,这不是该书的重要特征。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 2017-08-30
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多