模板专业化不适用于派生类 [英] Template Specialization Not Working with Derived Class

查看:26
本文介绍了模板专业化不适用于派生类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

这是我的代码:

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) 可以接受任何类型的参数......除了类型基类.

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

所以我专门为 Base 类型的参数使用 doSomething 模板,所以它做了一些不同的事情.

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

然而,当我将派生类传递给 doSomething 时,它会打印所有类型!",而我预计它会打印基类!",因为派生类本质上也是基类.

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.

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

Why does this specialization not work for Derived?

有什么办法让它工作吗?

Any way to make it work?

谢谢

>>> 测试链接<<<<


更新:

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

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

如果我改为:

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

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

然后 doSomething(d) 也会打印所有类型!"而不是Base!",因为 Derived2 对象将被简单地视为类型模板参数

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

推荐答案

当你 doSomething(Derived) 时,你导致你的 templateT 推测性地实例化=派生.

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

这有效(没有 SFINAE),所以它成为一个候选.

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

doSomething(Base) 要么不被考虑,要么是比 doSomething(Derived) 更差的匹配.

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

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

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

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

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

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

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.

首先,标签调度.

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

(将 {} 替换为 (),并在 C++03 中删除 std::forward)

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

在这里,我们明确地将 Base 的派生类路由到不同的覆盖.

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

另一种方法是 SFINAE 将 template 排除在考虑之外,并进行覆盖:

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 */ }

现在 template 版本被 SFINAE 排除在考虑之外,而是使用覆盖.

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

我发现标签调度更干净.

I find tag dispatching to be more clean.

这篇关于模板专业化不适用于派生类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆