Template Specialization Not Working with Derived Class

半世苍凉 提交于 2021-02-07 08:44:36

问题


I'm doing template specialization for one of my classes, and I'm experiencing something unexpected..

This is my code:

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;
}

I have a template function doSomething(T) that accepts parameters of any type.. except for type Base class.

So I specialized the doSomething template for parameter of type Base,, so it does something different.

When I pass a Derived class to doSomething, however, it prints "All Types!", while I expected it to print "Base!", because Derived class is essentially a Base class too.

Why does this specialization not work for Derived?

Any way to make it work?

Thanks

>>> Test Link <<<


UPDATE:

Someone mentioned overriding instead of template specializing.. but how would I override function in this case?

If I instead had:

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

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

then doSomething(d) would also print "All Types!" instead of "Base!",, because Derived2 object would simply be considered as Type template parameter


回答1:


When you doSomething(Derived) you cause your template to be speculatively instantiated with T=Derived.

This works (no SFINAE), so it becomes a candidate.

doSomething(Base) is either not considered, or is a worse match than doSomething(Derived).

Specialization simply changes the implementation of that one instantiation of doSomething. It does not change how it is considered at all.

Overriding adds another override, which then competes with your template version using the usual rules.

There are a few ways we can route calls to doSomething that are passed a Base or any class derived from base to a single implementation. I'll show 2.

First, tag dispatching.

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) );
}

(replace {} with (), and drop std::forward<T> in C++03)

Here, we explicitly route derived classes of Base to a different override.

Another approach would be to SFINAE exclude the template from consideration, and have an override:

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

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

now the template version is excluded from consideration by SFINAE, and the override is used instead.

I find tag dispatching to be more clean.




回答2:


You might solve it with 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;
}

Note: The argument is const T&, but having T as argument avoids the mentioned slicing, already.

Note: typename std::enable_if<std::is_base_of<Base, T>::value>::type is the return type, which is an optional second template parameter of std::enable_if, defaulting to void.



来源:https://stackoverflow.com/questions/25064214/template-specialization-not-working-with-derived-class

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!