Предположим, что у нас есть некоторый класс преобразования. Если мы сможем преобразовать из класса T
в U
, мы автоматически можем преобразовать наоборот.
Я представляю его с классом шаблона и некоторыми специализациями:
template <typename T, typename U>
class Convert;
template <>
class Convert<A,B> {
static int param() { return 42; }
}
template <>
class Convert<B,A> {
static int param() { return -Convert<A,B>::param(); }
}
Это работает хорошо, но когда нам нужно добавить новый тип для рутины, мы должны добавить 2 специализации. Можем ли мы уменьшить это число до 1, определив какой-то общий класс обратного шаблона следующим образом:
template <typename T, typename U>
class Convert {
static int param() { return -Convert<U,T>::param(); }
}
который мог бы работать, если у нас уже есть специализация Convert?
Заранее спасибо.
Вот предложение в моем комментарии:
#include<iostream>
#include<type_traits>
struct A{};
struct B{};
struct C{};
template <typename ... Args>
struct Convert;
template <typename T>
struct Convert<T,T> {
static int param() { return 0; }
};
template <typename T, typename U>
struct Convert<T,U> {
static decltype(-Convert<U,T>::param()) param() { return -Convert<U,T>::param(); }
};
template <>
struct Convert<A,B> {
static int param() { return 42; }
};
template <>
struct Convert<A,C> {
static int param() { return 43; }
};
template <>
struct Convert<B,C> {
static int param() { return 44; }
};
int main()
{
std::cout<<Convert<A,B>::param()<<std::endl;
std::cout<<Convert<B,A>::param()<<std::endl;
std::cout<<Convert<A,C>::param()<<std::endl;
std::cout<<Convert<C,A>::param()<<std::endl;
std::cout<<Convert<B,C>::param()<<std::endl;
std::cout<<Convert<C,B>::param()<<std::endl;
Convert<int,double>::param();
}
Идея состоит в том, чтобы однажды дать общее объявление, а затем сначала указать случай, когда аргументы шаблона равны (что должно давать нуль), а также случай, когда они различны, в которые возвращается преобразованный параметр.
Далее, для n
классов вам необходимо предоставить специализации для всех классов n*(n-1)/2
Convert
. (в случае, если это необходимо, это может быть дополнительно упрощено путем деривации, например).
T
нам, возможно, понадобится специализация с 2 аргументами. struct Convert<T,T>
. В противном случае этот Convert<A,A>::param()
не сможет скомпилироваться.