【问题标题】:Why is C++ numeric_limits<enum_type>::max() == 0?为什么 C++ numeric_limits<enum_type>::max() == 0?
【发布时间】:2012-03-01 09:25:19
【问题描述】:

这里有一些看起来可以工作的代码:

#include <cassert>
#include <limits>

enum test { A = 1 };

int main()
{
    int max = std::numeric_limits<test>::max();
    assert(max > 0);
}

但它在 Linux 上的 GCC (4.6.2) 和 clang (2.9) 下都失败了:枚举类型的 max() 实际上为零!即使您使用 C++11 枚举类型说明符明确说明您希望枚举具有什么类型,这仍然是正确的。

这是为什么?至于 C++11 的行为,是否有明确要求?我在关于强类型枚举的论文 N2347 中没有提到它。

【问题讨论】:

  • 你期望的值是多少?
  • is_specialized 的结果是什么?
  • @JamesMcNellis:我假设他希望它与 numeric_limits::max. 相同
  • @RaptorFactor:不过,这不是test 对象可表示的最大值。 test 对象可表示的最大值为1
  • @JohnZwinck:您可以查看is_specialized。如果不是这样,那么所有值都应该被认为是无意义的。

标签: c++ enums c++11 numeric-limits strongly-typed-enum


【解决方案1】:

std::numeric_limits 专门用于标准库“针对每种算术类型,包括浮点和整数,包括 bool”(第 18.3.2.1/2 节)。

您的枚举test 不是这些类型之一,因此使用主模板。其行为由 §18.3.2.3/1 指定:“默认 numeric_limits&lt;T&gt; 模板应具有所有成员,但具有 0false 值。”

如果你想知道test的底层类型的特征,可以使用underlying_type

std::numeric_limits<std::underlying_type<test>::type>::max()

或者,您可以将numeric_limits 专门用于test 并让它返回您想要的值。不过,这并不是一个特别好的主意。

【讨论】:

  • @RobKennedy:充其量是奇怪的,最坏的情况是误导。您不能为所有枚举专门化一次(因为标准库中有枚举),因此您必须为每个单独的枚举专门化它。那么,价值观应该是什么?您不能真正直接遵循underlying_type,因为底层类型可表示的最大值不一定是枚举可表示的最大值(例如,如果testint 表示,则最大int 值可能是2^32-1,但test 的最大值是1
  • 为什么有人甚至想为所有枚举专门化一次?通常,人们会对这个特定的test 枚举的专业化感兴趣。不会有什么问题吧?
  • 我不希望能够依赖底层类型。如果这是可能的,我们就不需要一开始就专攻。从事专业化的人大概知道该类型的属性,并且可以相应地实现numeric_limits 函数。如果有很多枚举类型,这将是乏味的,但我不会说这很奇怪。似乎是一个体面的结构,用于统一描述枚举的属性。危险在于让枚举的定义与相应的numeric_limits 特化不同步。
  • @jrok:除了尴尬和误导之外?不,这并没有
  • @RobKennedy:如果你想获得一个枚举的特征,写一个enum_traits,不要定义主模板,并将它专门用于单个枚举。
【解决方案2】:

对于模板的非专业版本,max 返回T()。您还没有为您的 test 类型编写 numeric_limits 特化,因此您获得了默认实现。

【讨论】:

【解决方案3】:

numeric_limits&lt;T&gt; 是一个常规的类模板,它没有以任何特殊方式连接到编译器以查找用户定义的enum 类型。如果您查看&lt;limits&gt; 文件,它具有默认模板定义,该定义为所有内容返回零,以及针对各个类型的一大堆特定类型的规范,返回正确的常量。

您可以通过自己提供numeric_limits&lt;test&gt; 的规范将您的enum“插入”到numeric_limits。您可以从&lt;limits&gt; 复制int 的那个,然后根据需要进行修改。

【讨论】:

    【解决方案4】:

    来自 C++11 草案:

    18.3.2.1,大约numeric_limits

    非算术标准类型,例如复数 (26.4.2),不应有特化。

    并且枚举不是算术标准类型。

    那么,在非特化模板中:

    template<class T> class numeric_limits {
        public:
        [...]
        static constexpr bool is_specialized = false;
        static constexpr T max() noexcept { return T(); }
    };
    

    即非特化max()函数返回该类型的默认初始化值,即0。

    【讨论】:

    • 枚举确实不是算术标准类型,但这并不意味着它是非算术标准类型。它根本不是任何一种标准类型。
    • @RobKennedy - 哦!你说的对!在这种情况下,该段没有任何意义。但这并没有改变重点:numeric_limits 不是专门用于枚举类型的。
    猜你喜欢
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 2023-03-20
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多