Page MenuHomePhabricator

Comparison with Enum Class Members
Closed, ResolvedPublic

Asked by mduminer on Nov 27 2019, 2:54 PM.

Details

I currently have the RIFT bytecode defined as follows:

enum class RIFTCodes
{
    EndFile = 0x00,
    EndInst = 0x01,
    // rest of the bytecode
}

But I need to test the actual bytecode against the RIFTCodes class, like this:

switch (code)
        {
        case RIFTCodes::Metadata:
            /* code */
            break;

However, that doesn't work, because Enum classes, as opposed to regular enums, do not allow direct use of their values.
So, according to this stack overflow answer, to solve this, I would have to call static_cast<std::byte>(RIFTCodes::Metadata). However, I would prefer to not clutter the code on every switch-case. So I would like to overload the comparison operator on the RIFTCodes class, like this:

bool RIFTCodes operator!=(const RIFTCodes& first, const std::byte& second)
{
    return second == static_cast<std::byte>(first);
};

However, it appears that RIFTCodes, is not a valid type, as enum classes are not types. So the first parameter is invalid.

So, what is the appropriate approach in this situation? Should I use a plain enum (I'm assuming that is not recommended), or use a static cast on every switch-case? Or is there a way to overload the comparison operator?

Answers

jcmcdonald
Updated 978 Days Ago

(EDITED)

Within a switch statement, each case must be an actual constant expression. That means, instead of using std::byte values or variables for case statements, you should be using hexadecimal literals (unsigned int, e.g. 0x01), or values from your enum class (RIFTCodes, e.g. RIFTCodes::SOME_CODE).

Depending on the type of code, you may need to implement overloaded operators. If codes is of type std::byte, you should define friend functions that compare std::byte to RIFTCode values. If codes is an instance of your own class, such as RIFTByte, you can implement many of the operator functions as members of that class.

Just remember that you must account for comparing in either direction. Since a == b is the same as b == a, either should work.

The following should allow you to compare between RIFTCodes and std::byte. These functions would be defined outside of the context of enum class RIFTCodes:

bool operator==(const RIFTCodes& lhs, const std::byte& rhs)
{
    return rhs == static_cast<std::byte>(lhs);
}

bool operator==(const std::byte& lhs, const RIFTCodes& rhs)
{
    return rhs == lhs;  // this should invoke the other version of the operator
}

bool operator!=(const RIFTCodes& lhs, const std::byte& rhs)
{
    return lhs != rhs;
}

bool operator==(const std::byte& lhs, const RIFTCodes& rhs)
{
    return rhs != lhs;
}

You'll note, because == and != are commutative, I only defined the logic once, and then had all the other versions of the function rely on that one shared implementation. Also, you'll notice that I needed to define both commutative forms!

I haven't tested this, but it should either work as-is, or be very close to the solution.

P.S. You'll see the parameter names lhs and rhs throughout our code. They stand for left-hand side and right-hand side respectively. It's a fairly common naming convention among C++ developers, and although not mandatory, I recommend it over first and second for binary operators.

New Answer

Answer

This question has been marked as closed, but you can still leave a new answer.