枚举运算符不起作用

时间:2018-06-29 19:19:15

标签: c++ enums operators

我的应用程序有很多位域枚举,需要各种支持功能(toString(),fromString(),countSetBits(),isValid()等)。因此,我使用CRTP来为具有所需功能的静态函数创建基类。一切都很好,除了,我无法让按位运算符起作用。所以...

为什么运算符1和2不允许A和B进行编译?

操作员3和4可以工作,他们对我来说也一样。 (实际上,4的实现无法编译,我也可以使用它来提供帮助。)(C样式强制转换仅用于节省空间)

陷入困境。请帮忙!

#include <type_traits>

using EnumUnderlying_t = unsigned;

template <typename EnumWrapper_t> struct EnumBitfieldBase {
    //CRTP allows for lots of handy static functions eliminating code duplication.  For example:
    static void test(){
        if constexpr (!std::is_same<EnumUnderlying_t, typename std::underlying_type<typename EnumWrapper_t::Enum>::type>::value){
        throw;
    }
}
//also: toString(), fromString(), countSetBits(), isValid(), largestValidValue(), allBitsSet() etc...
};

//operator #1
template <typename EnumWrapper_t>
inline constexpr typename EnumWrapper_t::Enum operator|(const typename EnumWrapper_t::Enum L, const typename EnumWrapper_t::Enum R) {
    return (typename EnumWrapper_t::Enum)((EnumUnderlying_t)L | (EnumUnderlying_t)R);
}

//operator #2
template <typename EnumWrapper_t>
inline constexpr typename EnumWrapper_t::Enum & operator|=(typename EnumWrapper_t::Enum & l, const typename EnumWrapper_t::Enum R) {
    return (typename EnumWrapper_t::Enum &)((EnumUnderlying_t &)l |= (EnumUnderlying_t)R);
}

struct Option : public EnumBitfieldBase<Option> {
    enum Enum : EnumUnderlying_t {
        None = 0,
        Lame = 1 << 0,
        Boring = 1 << 1,
        Stupid = 1 << 2
    };
};

/*
//operator #3
inline constexpr Option::Enum operator|(const Option::Enum L, const Option::Enum R) {
    return (Option::Enum)((EnumUnderlying_t)L | (EnumUnderlying_t)R);
}

//operator #4
inline constexpr Option::Enum & operator|=(Option::Enum & l, const Option::Enum R) {
        return (Option::Enum &)((EnumUnderlying_t &)l | (EnumUnderlying_t)R);
}
*/

int main(void) {
    Option::test();
    Option::Enum options{ Option::Lame | Option::Boring };//A -works only with c++17...why?
    options = (Option::Stupid | Option::Boring);//B -only works with operator #3
    options |= Option::Lame;//C -only works with operator #4
    if (options & Option::Lame) { /*do something lame*/ }
    return 0;
}

更新:好的,我发现运算符1和2将由于“非推断上下文”而无法工作。基本上,模板推导不适用于:: ...左侧的内容,那么对用作位域的枚举进行基类编程(或解决其问题)的正确方法是什么?我不想使用命名空间技巧,因为我需要类型来参与模板推导。有人吗?

2 个答案:

答案 0 :(得分:0)

您需要将它们声明为const方法;否则,它们将只允许在左值上使用,而您的常量则不是左值(它们是const,很笨拙)。

//operator #1
template <typename EnumWrapper_t>
inline constexpr typename EnumWrapper_t::Enum operator|(const typename EnumWrapper_t::Enum L, const typename EnumWrapper_t::Enum R) const {
    return (typename EnumWrapper_t::Enum)((EnumUnderlying_t)L | (EnumUnderlying_t)R);

(更改是第三行的最后一个字)

答案 1 :(得分:0)

这是使操作员1和2正常工作的最佳解决方案。如果您知道更好的方法,请发表!

//operator #1
template <typename T, typename = std::enable_if<std::is_enum<T>::value>>
inline constexpr T operator|(const T L, const T R)
{
    return static_cast<T>(static_cast<EnumUnderlying_t>(L) | static_cast<EnumUnderlying_t>(R));
}

//operator #2
template <typename T, typename = std::enable_if<std::is_enum<T>::value>>
inline constexpr T & operator|=(T & l, const T R)
{
    l = static_cast<T>(static_cast<EnumUnderlying_t>(l) | static_cast<EnumUnderlying_t>(R));
    return l;
}