I'm trying to do a templated user-defined-conversion that uses design by introspection.
In C++20 I can do the following:
template<typename T>
operator T() const
{
if constexpr( requires { PFMeta<T>::from_cursor(*this); } )
{
return PFMeta<T>::from_cursor(*this);
}
else
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
}
i.e. if PFMeta<T>::from_cursor(const struct PFCursor&)
is defined then use it else do a memcpy. (longer example here in godbolt: https://godbolt.org/z/abed1vsK3)
I love this approach but unfortunately this library will need to work on C++17 too.
So I've been trying SFINAE as an alternative to the concepts but it's very tricky.
I finally managed to get something similar but with a templated method as
rather than the user-defined-conversion operator itself:
template<typename T, typename = void>
struct has_from_cursor : std::false_type { };
template<typename T>
struct has_from_cursor<T, decltype( PFMeta<T>::from_cursor(std::declval<struct PFCursor>()), void() ) > : std::true_type { };
// ...
template<class T>
std::enable_if_t<has_from_cursor<T>::value, T> as() const
{
return PFMeta<T>::from_cursor(*this);
}
template<class T>
std::enable_if_t<!has_from_cursor<T>::value, T> as() const
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
I tried the following which compiles but does not work (I can't cast with it):
template<typename T>
operator std::enable_if_t<has_from_cursor<T>::value, T>() const
{
return PFMeta<T>::from_cursor(*this);
}
template<typename T>
operator std::enable_if_t<!has_from_cursor<T>::value, T>() const
{
T x;
std::memcpy(&x, &data, sizeof(x));
return x;
}
Longer example here: https://godbolt.org/z/5r9Mbo18h
So two questions:
- Can I do effectively what I can do with concepts with just SFINAE in C++17 for the user defined conversion operator?
- Is there a simpler way to do the
as
approach than the type traits &enable_if
? Ideally I'd like to do something like define the default templated method and then have a specialisation to be preferred if the condition is there (i.e. there is a meta class with a static member function defined).
Thanks!