The lack of implicit conversion can be painful when using scoped enums for bitwise flags:
enum class Flags: uint32_t { Foo = 1, Bar = 2 };
uint32_t foobar = Flags::Foo | Flags::Bar; // Error
I would tend to allow some implicit conversion with global operators such as:
template< typename T, typename R = typename std::underlying_type< T >::type, typename = typename std::enable_if< std::is_enum< T >::value && std::is_unsigned< R >::value >::type >
inline R operator |( T v1, T v2 )
{
return static_cast< R >( v1 ) | static_cast< R >( v2 );
}
template< typename T, typename R = typename std::underlying_type< T >::type, typename = typename std::enable_if< std::is_enum< T >::value && std::is_integral< R >::value >::type >
inline bool operator ==( R u, T v )
{
return u == static_cast< R >( v );
}
In which situation can these operators cause an issue or bug?
In the C++ FAQs we can read about scoped and strongly typed enums:
Conventional enums implicitly convert to int, causing errors when someone does not want an enumeration to act as an integer.
With the following example:
enum class Color { red, blue };
int i = Color::blue; // error: not Color->int conversion
I'm struggling to find an error scenario with such an implicit conversion to the underlying type, if the enum is an integral.
The need of static_cast
may IMHO also be dangerous, as it may silence a truncation:
enum class Color: uint64_t { red, blue = std::numeric_limits< uint64_t >::max() };
uint32_t i = static_cast< uint32_t >( Color::blue ); // No error, but invalid value
Of course, we should instead cast to the proper underlying type:
uint32_t i = static_cast< std::underlying_type< Color >::type >( Color::blue ); // OK, error here
But this is so ugly I doubt I'll be able to convince anyone in my team to use that...
Edit
Based on the (many) comments, here are some details.
I'm not suggesting implicit conversion should be added to C++.
I'm asking about the potential issues of introducing some global operators to help with that in an existing code base.
I would like everybody in my team to use scoped enums - But hard to convince them if they need to use static_casts
every time they have some bitwise flags, hence me trying to allow some implicit operations.