Транзитивная реализация шаблона

У меня есть шаблон преобразования, который должен преобразовывать указатели в типы, если преобразование безопасно. Это что-то вроде static_cast, но допускает пользовательские типы.

Пример: 2 представления сложных типов, одно как структура с двумя членами для real / imag, одно как массив с двумя элементами. Можно безопасно преобразовать указатель на один из них в указатель на другой.

Мои шаблоны выглядят так:

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);
}
};

То есть я могу конвертировать из Complex * в T * и из T * в fftw_complex *. Семантически это означает, что я также мог бы преобразовать из Complex * в fftw_complex *.

Но как я могу сказать компилятору, что это нормально? Я пробовал с:

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)));
}
};

и используйте это с парой базовых типов (double, float, int …), чтобы разрешить как минимум T-> base-> U, чего должно быть достаточно.

К сожалению, компилятор не находит специализацию для SafePtrCast< Сложный, fftw_complex >

Есть ли лучший способ справиться с этим? Что не так с моим шаблоном?

0

Решение

Как насчет использования черты:

template< typename T_Src, typename T_Dest, bool  >
struct Ptr2Ptr

// allowed conversion
template< typename T_Src, typename T_Dest>
struct Ptr2Ptr<T_Src, T_Dest, true>
{
using Src = T_Src;
using Dest = T_Dest;

static Dest* conv(Src* data) const
{
return reinterpret_cast<Dest*>(data);
}
};

template <typename T_Src, typename T_Dest>
conv_trait
{
static const bool enabled = false ;
}
template< typename T_Src, typename T_Dest>
struct SafePtrCast
{
T_Dest*
operator()(T_Src* data) const
{
return Ptr2Ptr<T_Src, T_Dest, conv_trait<T_Src, T_Dest>::value>::conv(data);
}
}

Теперь вы можете специализировать conv_trais для разрешенных конверсий.

template <class T>
conv_trait<Complex, T *>
{
static const bool value = true ;
}
0

Другие решения


По вопросам рекламы [email protected]