метод шаблона, соответствующий производному типу вместо базового

У меня есть набор операторов, которые мне нужно переопределить для шаблонов выражений. Я хотел бы, чтобы все производные классы базового типа соответствовали базовому типу. Другие вещи будут затем пойманы универсальным типом. К сожалению, универсальный тип захватывает производные типы раньше, чем базовый тип. Чтобы сделать вещи приятными и запутанными, все довольно сильно шаблонизировано, включая некоторые CRTP. Позвольте мне попытаться дать более простую версию кода:

// Note: 'R' is used for return type
template <typename DerivedType, typename R>
class Base
{ // ...
};

template <typename E1, typename E2, typename R>
class MultOperation : public Base<MultOperation<E1, E2, R>, R>
{ // ...
};

template <typename T>
class Terminal : public Base<Terminal<T>, T>
{ // ...
};

// The broken operators:
template <typename T1, typename T2, typename R1, typename R2>
MultOperation<Base<T1, R1>, Base<T2, R2>, typename boost::common_type<R1, R2>::type>
operator*( Base<T1, R1> const& u, Base<T2, R2> const& v)
{
return MultOperation<Base<T1, R1>, Base<T2, R2>, typename boost::common_type<R1, R2>::type>(u, v);
}

template <typename T1, typename T2, typename R1, typename R2>
MultOperation<Terminal<T1>, Base<T2, R2>, typename boost::common_type<T1, R2>::type>
operator*( T1 const& u, Base<T2, R2> const& v)
{
return MultOperation<Terminal<T1>, Base<T2, R2>, typename boost::common_type<T1, R2>::type>(Terminal<T1>(u), v);
}

template <typename T1, typename T2, typename R1, typename R2>
MultOperation<Base<T1, R1>, Terminal<T2>, typename boost::common_type<R1, T2>::type>
operator*( Base<T1, R1> const& u, T2 const& v)
{
return MultOperation<Base<T1, R1>, Terminal<T2>, typename boost::common_type<R1, T2>::type>(u, Terminal<T2>, v);
}

Теперь я не могу использовать какие-либо новые функции C ++. (Это часть некоторых рефакторингов для удаления старых библиотек, чтобы мы могли перейти на новые стандарты cpp.) Однако я могу использовать boost. Я думал, что мой ответ может лежать в boost::enable_if вещи, но все мои попытки привели к тупику. Теперь имейте в виду, что цель — шаблоны выражений, поэтому я не могу делать какие-либо вещи для приведения данных. Да … это так сложно … Я надеюсь, что у вас есть какая-то магия в вашем рукаве.

Краткая версия вопроса:
Как я могу получить (1 * Derived) * Derived соответствовать operator(T, Base) для первого оператора, затем operator(Base, Base) для второго оператора?
В настоящее время он соответствует первому штрафу, затем второй соответствует одному из базовых универсальных операторов, так как T не принимает преобразования и, следовательно, лучше, чем Base.

0

Решение

Вот черта, которая проверяет, является ли класс Base:

template<class T>
struct is_some_kind_of_Base {
typedef char yes;
typedef struct { char _[2]; } no;

template<class U, class V>
static yes test(Base<U, V> *);
static no test(...);

static const bool value = (sizeof(test((T*)0)) == sizeof(yes));
};

А затем ограничить ваши последние два operator*это как:

template <typename T1, typename T2,  typename R2>
typename boost::disable_if<is_some_kind_of_Base<T1>,
MultOperation<Terminal<T1>, Base<T2, R2>,
typename boost::common_type<T1, R2>::type> >::type
operator*( T1 const& u, Base<T2, R2> const& v) { /* ... */ }

демонстрация.

Предотвращать common_type чтобы не вызвать серьезную ошибку, нам нужно отложить ее оценку.

template <class T1, class T2, class R1, class R2>
struct make_mult_operation {
typedef MultOperation<T1, T2, typename boost::common_type<R1, R2>::type> type;
};

template <typename T1, typename T2,  typename R2>
typename boost::disable_if<is_some_kind_of_Base<T1>,
make_mult_operation<Terminal<T1>, T2, T1, R2> >::type::type
operator*( T1 const& u, Base<T2, R2> const& v) { /* ... */ }

демонстрация.

1

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

Я понимаю ваш вопрос, что вы хотите специализировать шаблон класса для типов, производных от данного базового типа. Я приведу пример без такого количества параметров шаблона.

Как вы и предполагали, идея в том, чтобы выбрать перегрузки через enable_if (Я использовал std::enable_if класс, но вы можете просто заменить std:: от boost:: для ваших целей):

template<typename T, typename U>
struct is_derived_from_base
{
static constexpr bool first = std::is_base_of<Base<T>, T>::value;
static constexpr bool second = std::is_base_of<Base<U>, U>::value;

static constexpr bool none = !first && !second;
static constexpr bool both = first && second;
static constexpr bool only_first = first && !second;
static constexpr bool only_second = !first && second;
};

template<typename T, typename U, typename = typename std::enable_if<is_derived_from_base<T,U>::none>::type >
auto operator*(T const& t, U const& u)
{
std::cout<<"Both T and U are not derived"<<std::endl;
return MultOperation<T, U>(t,u);
}template<typename T, typename U, typename = typename std::enable_if<is_derived_from_base<T,U>::only_first>::type >
auto operator*(Base<T> const& t, U const& u)
{
std::cout<<"T is derived from Base<T>, U is not derived"<<std::endl;
return MultOperation<Base<T>, U>(t,u);
}

template<typename T, typename U, typename = typename std::enable_if<is_derived_from_base<T,U>::only_second>::type >
auto operator*(T const& t, Base<U> const& u)
{
std::cout<<"T is not derived, U is derived from Base<U>"<<std::endl;
return MultOperation<T, Base<U> >(t,u);
}

template<typename T, typename U, typename = typename std::enable_if<is_derived_from_base<T,U>::both>::type >
auto operator*(Base<T> const& t, Base<U> const& u)
{
std::cout<<"T is derived from Base<T>, U is derived from Base<U>"<<std::endl;
return MultOperation<Base<T>, Base<U> >(t,u);
}

Для более подробной информации смотрите полную программу Вот.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector