Reputation: 11
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
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 i
th 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