2

This is closely related to Are C++ enums signed or unsigned?. According to JavaMan's answer, an enum is neither signed nor unsigned. But it does follow integral promotion rules.

I'm working with a library that uses enums and then passes them to other class objects that expect mostly unsigned types (like unsigned int and size_t). Enabling the -Wsign-conversion warning in an effort to catch legitimate mistakes is causing a number false positives due to the language's rules.

The rule kind of creates a a situation where its difficult to ensure type safety and catch common mistakes. Its difficult because I want to avoid things like static_cast sprinkled liberally throughout the code.

Is there a way to override the language's default behavior for promoting enums to concrete signed or unsigned types? (Similar to the way you can specify a char is signed or unsigned).


Related, the library was written in the 1990s, so it supports a number of older compilers. It would be great if the solution addressed even C++03 and possibly earlier.

From How to guard move constructors for C++03 and C++11?, I know there's no reliable way in practice to detect when other C++ language variants are in effect. It fell flat on its face during testing with Clang 3.5 using -std=c++03 and -std=c++11.

Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
  • 1
    Can you use C++11, and can you modify the enum definitions in this library? – Praetorian Jul 06 '15 at 06:48
  • @Praetorian - Unfortunately, no, we can't depend upon C++11. We still need to support C++03 (and possibly earlier). On the good side, I can modify the enum definitions in the library. If needed, the library is Wei Dai's [Crypto++](http://www.cryptopp.com/). Sorry about not providing that information sooner. – jww Jul 06 '15 at 07:04

2 Answers2

2

The underlying type of a C++03 enumeration depends on the range of values of its enumerators, and it promotes to its underlying type, not int (C++98 [conv.prom] §4.5/2).

The dirty way to force an enumeration to behave as unsigned int is to add a value that only unsigned int can handle.

enum things {
    a, b, c,
    force_unsigned = -1U
};

Demo: http://coliru.stacked-crooked.com/a/d3ded108fb5a68bf

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • had to scratch my head what the "-1u" will result in, this helped me: http://brnz.org/hbr/?p=1433 – user2950911 Jul 06 '15 at 11:00
  • @user2950911 Yeah, and it's important that `-1u` is a positive number. All the enumerator values need to be positive for this to work, or the compiler will be forced choose `signed long` or `signed long long`, which can hold both `-1u` and proper negative numbers. – Potatoswatter Jul 06 '15 at 15:35
1

You can roll your own enum class:

struct safe_enum {
    enum type {
        value1, value2, value3
    };
    type value;

    operator unsigned int ()
        { return value; }
};

safe_enum foo = safe_enum::value1;
unsigned bar = safe_enum::value2;

Unfortunately, this loses the "unscoped" behavior of C++03 enumerations, so this best-practice pattern will break the codebase. Also, changing an enum into a class will break the ABI, if this has been shipped as a DLL.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421