繁体   English   中英

模板专业化不适用于派生类

[英]Template Specialization Not Working with Derived Class

我正在为我的一个班级做模板专业化,而且我遇到了意想不到的事情......

这是我的代码:

class Base {};
class Derived : public Base {};

template<typename T>
void doSomething(T t) { cout << "All Types!" << endl; }

template<>
void doSomething(Base b) { cout << "Base!" << endl; }

int main() {
    Derived d;
    doSomething(d);       //prints "All Types!"

    return 0;
}

我有一个模板函数doSomething(T)接受任何类型的参数..除了类型基类。

所以我将doSomething模板专门用于Base类型的参数,所以它做了不同的事情。

然而,当我将Derived类传递给doSomething时,它会打印“All Types!”,而我期望它打印“Base!”,因为Derived类本质上也是一个Base类。

为什么这种专业化不适用于Derived?

有什么方法可以使它工作?

谢谢

>>>测试链接<<<


更新:

有人提到覆盖而不是模板专门化..但在这种情况下如何覆盖函数?

如果我改为:

template<typename T>
void doSomething(T t) { cout << "All Types!" << endl; }

void doSomething(Base b) { cout << "Base!" << endl; }    

然后doSomething(d)还会打印“All Types!” 而不是“Base!”,因为Derived2对象将被简单地视为Type模板参数

您可以使用std :: enable_if解决它:

#include <type_traits>
#include <iostream>

class Base {};
class Derived1 : public Base {};
class Derived2 : public Derived1 {};

template<typename T>
typename std::enable_if< ! std::is_base_of<Base, T>::value>::type
doSomething(const T&) { std::cout << "All Types!" << std::endl; }

template<typename T>
typename std::enable_if<std::is_base_of<Base, T>::value>::type
doSomething(const T&) { std::cout << "Base or Derived!" << std::endl; }

int main() {
    // All Types!
    doSomething(1);
    // Base or Derived!
    doSomething(Base());
    doSomething(Derived1());
    doSomething(Derived2());

    return 0;
}

注意:参数是const T& ,但是将T作为参数避免了已提到的切片。

注意: typename std::enable_if<std::is_base_of<Base, T>::value>::type是返回类型,它是std :: enable_if的可选第二个模板参数,默认为void。

当您执行doSomething(Derived)您的template将通过T=Derived进行推测性实例化。

这有效(没有SFINAE),因此它成为候选人。

doSomething(Base)要么不被考虑,要么比doSomething(Derived)更糟糕。

专业化只是改变了doSomething一个实例化的实现。 它根本不会改变它的考虑方式。

覆盖会添加另一个覆盖,然后使用通常的规则与您的template版本竞争。

我们可以通过几种方法将调用doSomething方法路由到Base或从base派生的任何类到单个实现。 我会展示2。

首先,标签调度。

namespace aux {
  template<class T> void doSomething( std::true_type /* is Base */, T t ) {
    // T is a class derived from Base
  }
  template<class T> void doSomething( std::false_type /* is Base */, T t ) {
    // T is not class derived from Base
  }
}
template<class T> void doSomething( T t ) {
  aux::doSomething( std::is_base_of< Base, T >{}, std::forward<T>(t) );
}

(替换{}()和降std::forward<T>在C ++ 03)

在这里,我们显式地将派生的Base类路由到不同的覆盖。

另一种方法是SFINAE排除考虑的template ,并具有覆盖:

template<class T>
typename std::enable_if< !std::is_base_of<Base, T>::value >::type
doSomething( T t ) { /* blah */ }

void doSomething( Base b ) { /* foo */ }

现在,SFINAE不考虑template版本,而是使用覆盖。

我发现标签调度更干净。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM