Отсутствие неявного преобразования может быть болезненным при использовании перечислений с областью видимости для побитовых флагов:
enum class Flags: uint32_t { Foo = 1, Bar = 2 };
uint32_t foobar = Flags::Foo | Flags::Bar; // Error
Я хотел бы разрешить некоторое неявное преобразование с глобальными операторами, такими как:
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 );
}
В какой ситуации эти операторы могут вызвать проблему или ошибку?
В часто задаваемых вопросах по C ++ мы можем прочитать о ограниченных и строго типизированных перечислениях:
Обычные перечисления неявно преобразуются в int, вызывая ошибки, когда кто-то не хочет, чтобы перечисление действовало как целое число.
В следующем примере:
enum class Color { red, blue };
int i = Color::blue; // error: not Color->int conversion
I Я изо всех сил пытаюсь найти сценарий ошибки с таким неявным преобразованием в базовый тип, если enum является целым числом.
Необходимость static_cast
может ИМХО также быть опасной, поскольку она может отключить усечение:
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
Конечно, вместо этого мы должны привести к нужному базовому типу:
uint32_t i = static_cast< std::underlying_type< Color >::type >( Color::blue ); // OK, error here
Но это так ужасно, я сомневаюсь, что смогу убедить кого-либо в моей команде используйте это ...
Редактировать
Основываясь на (многих) комментариях, вот некоторые детали.
Я не предлагаю неявное преобразование в C ++.
Я спрашиваю о потенциальных проблемах введения некоторых глобальных операторов, чтобы помочь с этим в существующей кодовой базе.
Я хотел бы, чтобы все в моей команде использовали перечисления с ограниченным диапазоном - но трудно убедить их, если им нужно используйте static_casts
каждый раз, когда у них есть побитовые флаги, поэтому я пытаюсь разрешить некоторые неявные операции.