Search code examples
c++enumsdeserializationunderlyingtype

How to cast reference to enum to reference to underyling type (int)?


I'm working on a deserializer. The problem is that we have a lot of enums and I'm not gonna create overloads for each one of them. So I tried to first break the reference to enum down to a reference to its underlying type, but somehow it won't compile:

Live demo

#include <iostream>
#include <cstdint>
#include <type_traits>
#include <cstring>


enum class MyEnum : uint32_t
{
    one = 100,
    two,
};

auto deserialize(std::byte* addr, uint32_t& val)
{
    memcpy(&val, addr, sizeof(uint32_t));
}

int main()
{
    std::byte buf[4] = { std::byte{0x00}, std::byte{0x00}, std::byte{0x00}, std::byte{0x64}};

    MyEnum val;
    
    using underlying_type = std::underlying_type_t<decltype(val)>&;
    deserialize(buf, static_cast<underlying_type>(val));

    std::cout << val << std::endl;
}

How can I get this to work?


Solution

  • Forget it. If you have an enum type, writing to it as if it were of its underlying type violates the strict aliasing rule. It's not hard to make the code compile (just use reinterpret_cast instead of static_cast) but the behaviour will be undefined due to the strict aliasing violation.

    You have to deserialize into a proper uint32_t and then copy its value into the destination enum, for example:

    template <class Enum>
    requires std::is_enum_v<Enum>
    void deserialize(std::byte* addr, Enum& val)
    {
        std::underlying_type_t<Enum> underlying;
        deserialize(addr, underlying);
        val = static_cast<Enum>(underlying);
    }
    

    Or, I mean, why not just memcpy directly into the enum like you do with the uint32_t?

    template <class Enum>
    requires std::is_enum_v<Enum>
    void deserialize(std::byte* addr, Enum& val)
    {
        memcpy(&val, addr, sizeof(Enum));
    }
    

    There's no reason to write a separate overload per enum.