template <class E>
E& operator|=(E& a, const E& b) noexcept {
using underlying = std::underlying_type_t<E>;
auto underlying_a = static_cast<underlying>(a);
auto underlying_b = static_cast<underlying>(b);
a = static_cast<E>(underlying_a | underlying_b);
return a;
}
问题是它很乐意接受
任何类型
并且会以通常意想不到的方式造成麻烦和干扰代码的其他部分。我强烈建议不要使用这个版本,即使操作符位于名称空间后面。
所以它需要
受限制的
只是想要的类型。我将使用概念,因为它们更有表现力。对于C++前20,很容易转换成经典的SIFAE技术。
一个快速解决方案是只接受枚举:
template <class E>
requires std::is_enum_v<E>
E& operator|=(E& a, const E& b) noexcept {
using underlying = std::underlying_type_t<E>;
auto underlying_a = static_cast<underlying>(a);
auto underlying_b = static_cast<underlying>(b);
a = static_cast<E>(underlying_a | underlying_b);
return a;
}
template <class E> struct IsAwesomeEnum: std::false_type {};
template <> struct IsAwesomeEnum<ScopedEnumFoo> : std::true_type {};
template <> struct IsAwesomeEnum<ScopedEnumBar> : std::true_type {};
template <class E>
requires IsAwesomeEnum<E>::value
E& operator|=(E& a, const E& b) noexcept {
using underlying = std::underlying_type_t<E>;
auto underlying_a = static_cast<underlying>(a);
auto underlying_b = static_cast<underlying>(b);
a = static_cast<E>(underlying_a | underlying_b);
return a;
}
我会更进一步,为它定义一个概念:
template <class E>
concept AwesomeEnum = IsAwesomeEnum<E>::value;
template <AwesomeEnum E>
E& operator|=(E& a, const E& b) noexcept {
using underlying = std::underlying_type_t<E>;
auto underlying_a = static_cast<underlying>(a);
auto underlying_b = static_cast<underlying>(b);
a = static_cast<E>(underlying_a | underlying_b);
return a;
}
为了完整起见,这里有一种非概念SFINAE方法:
template <class E, class = std::enable_if_t<IsAwesomeEnum<E>::value>>
E& operator|=(E& a, const E& b) noexcept {
using underlying = std::underlying_type_t<E>;
auto underlying_a = static_cast<underlying>(a);
auto underlying_b = static_cast<underlying>(b);
a = static_cast<E>(underlying_a | underlying_b);
return a;
}