I'm trying to reimplement memchr as constexpr (1). I haven't expected issues as I have already successfully done the same thing with strchr which is very simmilar.
However both clang and gcc refuse to cast const void* to anything else within constexpr function, which prevents me to access the actual values.
I understand that working with void* in constexpr function is weird, as we cannot do malloc and there is no way to specify arbitrary data as literal values. I'm doing this basically as a part of an excercise to rewrite as much as I can from as constexpr (2).
Still I'd like to know why this is not allowed and if there is any way around it.
Thank you!
(1) My implementation of memchr:
constexpr void const *memchr(const void *ptr, int ch, size_t count) {
const auto block_address = static_cast<const uint8_t *>(ptr);
const auto needle = static_cast<uint8_t>(ch);
for (uintptr_t pos{0}; pos < count; pos) {
auto byte_address = block_address pos;
const uint8_t value = *byte_address;
if (needle == value) {
return static_cast<void const *>(byte_address);
}
}
return nullptr;
}
(2) The entire project on Github: https://github.com/jlanik/constexprstring
CodePudding user response:
No, it is impossible to use void*
in such a way in constant expressions. Casts from void*
to other object pointer types are forbidden in constant expressions. reinterpret_cast
is forbidden as well.
This is probably intentional to make it impossible to access the object representation at compile-time.
You cannot have a memchr
with its usual signature at compile-time.
The best that I think you can do is write the function for pointers to char
and its cv-qualified versions, as well as std::byte
(either as overloads or as template), instead of void*
.
For pointers to objects of other types it is going to be tricky in some cases and impossible in most cases to implement the exact semantics of memchr
.
While I am not certain that it is possible, maybe, in a templated version of memchr
, one can read the underlying bytes of the objects passed-by-pointer via a std::bit_cast
into a struct containing a std::byte
/unsigned char
array of appropriate size.