选择专用于派生实例的基类的类模板

时间:2018-05-29 21:42:38

标签: c++ templates

考虑以下示例程序:

#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 :(得分:4)

使用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"; }
};

Demo

答案 1 :(得分:3)

模板专业化适用于字面上相同的类型。如果您使用Base专用模板,则此专精化不适用于Derived

解决此问题的一种方法是使用您为Base派生的类型启用的部分特化。