Выберите шаблон класса, специализированный для базового класса производного экземпляра. - PullRequest
0 голосов
/ 30 мая 2018

Рассмотрим следующий пример программы:

#include <iostream>

template<typename T>
struct Dispatch
{
    static void send(T&) { std::cout << "unknown\n"; }
};

struct Processor
{
    template<typename T>
    void process(T&& t) { Dispatch<T>::send(t); }
};

template<typename T>
struct Base
{};

template<typename T>
struct Dispatch<Base<T>>
{
    static void send(Base<T>&) { std::cout << "base\n"; }
};

struct Deriv : Base<int>
{};

int main()
{
    Processor p;
    p.process(Base<int>{}); // prints "base"
    p.process(Deriv{});     // prints "unknown"
    return 0;
}

При вызове Processor::process() с экземпляром Deriv (который является подклассом Base), я бы хотел, чтобы Dispatcher() специализировался для Base шаблоны классов для выбора.

Однако в приведенном выше примере происходит следующее:

  • передача экземпляра Base<T> в process() вызывает специализацию Base<T>
  • передача экземпляра Deriv в process() вызывает шаблон основного класса

Вопрос:

  • Почему Base<T> не лучшая специализация для Deriv, чем шаблон основного класса?
  • Существует ли общий способ вызова специализации Base<T> при передаче подклассов Base<T>?

Ответы [ 2 ]

0 голосов
/ 30 мая 2018

Шаблон специализации работает для буквально одного типа.Если вы специализировали шаблон для Base, эта специализация не будет работать для Derived.

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

0 голосов
/ 30 мая 2018

С SFINAE вы можете сделать:

// Traits to detect inheritance:
template <typename T> std::true_type derive_from_base_impl(Base<T>*);
std::false_type derive_from_base_impl(...);

template <typename T>
using derive_from_base_t = decltype(derive_from_base_impl(std::declval<T*>()));

Затем некоторые изменения

template<typename T, typename Enabler = void>
struct Dispatch
{
    static void send(T&) { std::cout << "unknown\n"; }
};

template<typename T>
struct Dispatch<T, std::enable_if_t<derive_from_base_t<T>::value>>
{
    static void send(T&) { std::cout << "base\n"; }
};

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...