纯虚函数的模板特化

Template specialization of pure virtual function

如何专门化在基 class 中定义为纯函数的模板化函数?

struct A {
    virtual void func(int a) = 0;
    //virtual void func(int a) {} // replace above line with this and it works
};

struct B : public A {
    template<typename T> void func(T t) {
        cout <<"hello"<<endl;
    }
};
template<> void B::func<int>(int a) { cout <<"hello 2"<<endl; }


int main() {
    B b;
    b.func(2);
}

错误:

error: variable type 'B' is an abstract class B b; ^ note: unimplemented pure virtual method 'func' in 'B' virtual void func(int a) = 0;

虚函数只能被 non-template 函数覆盖。在这种情况下,

Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration) and overrides Base::vf (whether or not the word override is used in its declaration).

注意函数模板不能是virtual functions

Functions templates cannot be declared virtual.

根据标准,[temp.mem]/4

A specialization of a member function template does not override a virtual function from a base class. [ Example:

class B {
  virtual void f(int);
};

class D : public B {
  template <class T> void f(T); // does not override B​::​f(int)
  void f(int i) { f<>(i); }     // overriding function that calls the template instantiation
};

— end example ]

关于你的问题,

why it works if the function is made 'not pure'?

编译错误消失了,但仍然没有达到预期效果;派生 class 中的函数模板不会 覆盖 基础 class 的虚函数。您可以使用 dynamic dispatch:

检查

If a derived class is handled using pointer or reference to the base class, a call to an overridden virtual function would invoke the behavior defined in the derived class.

请注意,您应该使用指针或引用来进行动态调度,例如

B b;
A* pa = &b;
pa->func(2);

LIVE

您也可以申请override specifier来帮助您确认覆盖

//virtual void func(int a) {} // replace above line with this and it works

替换上面的行,代码编译,不起作用。

或者,更好的是,有效,但不像您预期​​的那样。

问题是 virtual 函数和 template 函数不能很好地混合。

所以你不能制作直接覆盖虚函数的模板函数:如果你定义func()为空虚函数

virtual void func(int a) = 0;

基础 A class 和所有派生的 classes,变成 not-instantiable 直到你没有定义一个有效的 virtual func()函数。

正在定义

virtual void func(int a) {}

基础 A class 和所有派生类不再是 not-instantiable 因为您不再需要重新定义虚函数。

但是templatefunc()版本与虚函数无关

当你在main()中调用b.func(2)时,是template,而不是继承自Avirtual func(),即叫。这是因为 template func() "hide" func() 继承了 virtual 版本。

你可以"un-hide"在Bvirtualfunc()版本中添加,在B的正文中定义

using A::func;

这样,在main()中调用b.func(2);,调用A继承的virtual版本和func()的模板特化,所以std::cout <<"hello 2" << std::endl; 指令,不再执行。

现在...如果我理解正确的话,你想要一个 template func() 函数,以防 T == int 加入虚拟专业化。

我看到的唯一方法是在 B

中定义 virtual override
void func (int a) override // override, so necessarily virtual
 { std::cout <<"hello 2" << std::endl; }  

并从 template 专业化

调用它
template <>
void B::func<int> (int a)
 { func(a); } // call the virtual override version

下面是一个完整的编译示例

#include <iostream>

struct A
 { virtual void func(int a) = 0; };

struct B : public A
 {
   void func (int a) override
    { std::cout <<"hello 2" << std::endl; }

   template<typename T>
   void func (T t)
    { std::cout << "hello" << std::endl; }
 };

template <>
void B::func<int> (int a)
 { func(a); }


int main ()
 {
   B{}.func(2); // call directly virtual func()
   B{}.func<int>(2); // call template func() specialization that call virtual func()
 }

这可能不是重点,但在使用模板进行设计时可以使用一个非常好的助记符:

虚函数——动态多态(通过vtable在运行时解决)

模板特化-静态多态(在编译时通过类型信息解决)

不要试图用一个来解决另一个。

在您的情况下,您正试图通过模板特化向虚方法提供主体(解决运行时多态性)。