Reputation: 1356
I'm implementing a simple variant class (mainly for practice) and I've come to a problem with type decaying. I would like to create a constructor that takes a sub-type of the variant and constructs it accordingly (case (4) here, the converting constructor).
For copying and moving, I have a helper class that contains functions like this:
static inline void copy(std::size_t old_type_id, void* old_data, void* new_data);
static inline void move(std::size_t old_type_id, void* old_data, void* new_data);
So I'm passing everything as a void*
for simplicity. My converting constructor looks like this:
template <typename T>
variant(T&& v)
: type_id{ typeid(std::decay_t<T>).hash_code() } {
if constexpr (std::is_lvalue_reference_v<T>) {
helper_type::copy(type_id, reinterpret_cast<void*>(&v), &data);
}
else {
helper_type::move(type_id, reinterpret_cast<void*>(&v), &data);
}
}
My idea was to check if this is a reference, because then we can only copy, otherwise move. But because v
is a templated parameter, there is no automatic decaying of types, and if I try to pass a C-style string, I get errors like:
cannot convert from 'const char (*)[6]' to 'void *'
Is there a way to do this kind of conversion without specializing every decaying type?
Upvotes: 1
Views: 89
Reputation: 49028
As @liliscent says, you need to use const void*
.
This is because even though void*
can accept any type of pointer, it is still bound to the rules that state that a conversion from const T*
to T*
is ill-formed if you don't use const_cast
(which you shouldn't in this case).
Upvotes: 1