I have a conversion template, that should convert between pointers to types if the conversion is safe. That is something like static_cast but allows user defined types.
Example: 2 representations of complex types, one as a struct with 2 members for real/imag, one as a array with 2 elements. It is safe to convert a pointer to one of them to a pointer to the other.
My templates looks like this:
template< typename T_Src, typename T_Dest, typename T_SFINAE = void >
struct SafePtrCast;
template< typename T >
struct SafePtrCast< Complex<T>*, T* >
{
T*
operator()(Complex<T>* data)
{
return &data->real;
}
};
template< typename T >
struct SafePtrCast< T*, fftw_complex* >
:Ptr2Ptr<T, fftw_complex>{};
template< typename T_Src, typename T_Dest = T_Src >
struct Ptr2Ptr
{
using Src = T_Src;
using Dest = T_Dest;
Dest*
operator()(Src* data) const
{
return reinterpret_cast<Dest*>(data);
}
};
That is, I can convert from Complex* to T* and from T* to fftw_complex*. Semantically this means I could also convert from Complex* to fftw_complex*.
But how can I tell the compiler, that this is ok? I tried with:
template< typename T_Src, typename T_Dest >
struct SafePtrCast<
T_Src,
T_Dest,
void_t< std::result_of_t<
SafePtrCast<
std::result_of_t<
SafePtrCast<T_Src, double* >
>,
T_Dest
>
> >
>{
using Conv1 = SafePtrCast< T_Src, double* >;
using Conv2 = SafePtrCast< double*, T_Dest >;
T_Dest
operator()(T_Src&& data) const
{
return Conv2(Conv1(std::forward<T_Src>(data)));
}
};
and use this with a couple of base types (double, float, int...) to allow at least T->base->U which should be enough.
Unfortunately the compiler does not seem to find the specialization for SafePtrCast< Complex, fftw_complex >
Is there a better way to deal with this? Whats wrong with my template?
What about using a trait:
Now you can specialize the conv_trais for allowed conversions