C++ 模板专门化不适用于派生类

C++ 模板专门化不适用于派生类,c++,templates,C++,Templates,我正在为我的一个类进行模板专门化,我遇到了一些意想不到的事情 这是我的代码: class Base {}; class Derived : public Base {}; template<typename T> void doSomething(T t) { cout << "All Types!" << endl; } template<> void doSomething(Base b) { cout << "Base!" &

我正在为我的一个类进行模板专门化,我遇到了一些意想不到的事情

这是我的代码:

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;
}
类基{};
派生类:公共基{};
模板

void doSomething(T){cout您可以使用std::enable_解决它,如果:

#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;
}
#包括
#包括
类基{};
类Derived1:公共基{};
类Derived2:公共Derived1{};
模板
typename std::enable_如果<!std::is_base_of::value>::type
doSomething(const T&){std::cout当您
doSomething(派生)
时,您会导致您的
模板
被推测性地实例化为
T=Derived

这是有效的(没有SFINAE),因此它成为候选

doSomething(Base)
要么不被考虑,要么是比
doSomething(派生)
更糟糕的匹配

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

覆盖添加另一个覆盖,然后使用常规规则与您的
模板
版本竞争

有几种方法可以将调用路由到
doSomething
,这些调用通过
Base
或从Base派生的任何类传递到单个实现

首先,标签调度

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) );
}
现在,SFINAE不考虑
模板
版本,而是使用覆盖


我发现标记分派更干净。

第1步:停止专门化函数。改为重写。重写和专门化以令人讨厌的方式相互作用。然后想想重写。@Yakk请查看我的更新。你真的打算切片你的派生对象吗?@n.m我认为这在我的情况下不重要。.我只想要函数重载ng/specialization to work..它实际上对基本对象本身有效吗?请注意,这会创建两个不同的
doSomething
,它不会专门化。非常棒的解决方案!!顺便问一下,在doSomething(const T&)前面省略“void”有什么原因吗声明?哦,如果返回类型是bool而不是void,我可以这样做:“typename std::enable_if<!std::is_base_of::value,bool>::type”?哇,很好的解决方案。顺便问一下,在doSomething(T)前面省略“void”有什么原因吗第二种解决方案中的声明?嗯,我想我们之前已经讨论过了——覆盖这个术语是否适用于标准调用重载,特别是考虑到新的“关键字”
override
?在这个意义上它是否常用?(我是不是太迂腐了?)我是confused@user2436815如果通过SFINAE,
enable_
将提供
void
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) );
}
template<class T>
typename std::enable_if< !std::is_base_of<Base, T>::value >::type
doSomething( T t ) { /* blah */ }

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