Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting struct to constexpr array of uint8_t

I need to create constexpr array of bytes out of constexpr struct.

#include <array>

template<typename T>
constexpr std::array<uint8_t, sizeof(T)> o2ba(const T o) {
    return {};
}

struct A {
    int a;
};

int main() {
    constexpr A x{ 1 };
    constexpr auto y = o2ba(x); // y == { 0x01, 0x00, 0x00, 0x00 } for little endian
    return 0;
}

I tried to extract it from union:

template<typename T>
union U {
    T o;
    std::array<uint8_t, sizeof(T)> d;
};

template<typename T>
constexpr std::array<uint8_t, sizeof(T)> o2ba(const T o) {
    return U<T>{o}.d;
}

but it fails on both gcc and msvc compilers for accessing d instead of initialized o member. It works when initializing non constexpr object though, as below.

int main() {
    constexpr A x{ 1 };
    auto y = o2ba(x); // y == { 0x01, 0x00, 0x00, 0x00 } for little endian
    return 0;
}

But that is not what I need. Is there a way to do this?

like image 1000
omicronns Avatar asked Jan 05 '18 10:01

omicronns


1 Answers

What you want is not possible. In your code, you try to access an initialized member in a constexpr context, which is fine. The error is that you then try to access a non-active member, which isn't permitted per [expr.const#2.8]:

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

...

  • an lvalue-to-rvalue conversion that is applied to a glvalue that refers to a non-active member of a union or a subobject thereof;

Now the alternative is to try to serialize the object to bytes the old fashion way, via reinterpret_cast, i.e reinterpret_cast<const uint8_t*>(&a). Again reinterpret_cast's aren't allowed allowed in a constexpr context per 2.15 (same section). I suspect that the reason why you cannot do this is because it's unportable.

like image 122
user6320840 Avatar answered Nov 20 '22 21:11

user6320840