GUCCISWAGDAWG
GUCCISWAGDAWG

Reputation: 11

Cast pointers in consteval

I wanted to make a compiletime data encryptor.
I tried this by creating a struct with a buffer, and a constructor for that struct that
would read an array of structures in that buffer. And because I wanted to use blockcypher,
I wanted that buffer length to be devideable by 16.

Here is my codesnippit:

    template <typename type, size_t len>
    struct DataPackage
    {
        unsigned char buffer[len * sizeof(type) + (16 - ((len * sizeof(type)) % 16))]; //create buffer to fit all types and fill to 16 byte blocks

        __forceinline consteval DataPackage(type data[len])
        {
            for (int i = 0; i < sizeof(buffer); i++)
                buffer[i] = i < len * sizeof(type) ? *(reinterpret_cast<unsigned char*>(data) + i) : '\0';
        
            //encrypt buffer here
        }
    };

It gives me the error:
conversation from 'type*' to 'unsigned char*' is invalid in constant expression evaluation.

I use visual c++ compiler with c++ 20.

Is there a way to cast a pointer to a pointer to a different type in a consteval function? Is there maybe a dirty compile hack workaround? What exactly is preventing me from this, could this be fixed in future versions of c++?

Upvotes: 0

Views: 430

Answers (1)

user17732522
user17732522

Reputation: 76794

It is impossible to reinterpret data as a different type in a constant expression, but you can cast the object representation to a different type if that is your intention:

auto obj_repr = std::bit_cast<std::array<unsigned char, sizeof(type)>>(data[i]);

Now obj_repr is an array of unsigned char containing the object representation of the ith element of the array. You can operate on that copy.

This requires of course that T is trivially-copyable. Otherwise your reinterpret_cast approach would have undefined behavior as well anyway. Furthermore to make this work as a constant expression type may not be or contain as subobject a pointer type, a union type, a pointer-to-member type, a volatile-qualified type or a reference type.

(There is some disagreement on whether theoretically this is always guaranteed to work because std::array may not be required to be free of padding, but it will work in practice. See e.g. std::bit_cast with std::array)


A consteval function can only be evaluated at compile-time. Therefore I highly doubt that __forceinline has any meaning on it, although of course that is purely implementation-defined and I don't know how MSVC handles it in this situation.

Usually consteval is not required over constexpr. I don't see anything in the code you are showing that needs to be prevented from being evaluated at runtime.

Upvotes: 1

Related Questions