专门针对派生类中的模板成员

时间:2018-11-05 20:53:32

标签: c++ templates

我有一个带有模板成员的基类,它专门用于某些情况。派生类进一步专门化了基类的模板成员。除此之外的基本原理是,模板成员的各种专业化都“适应”特定情况,“逻辑上”执行相同的工作。基类提供了一些模板特化,这些特化可在某些情况下执行任务,派生类应通过进一步特化模板成员来将同一任务“扩展”到其他情况。

这是说明我遇到的问题的最小示例。

#include <iostream>

struct A {
  template <int i>
  void dosomething();

  void show();
};

template<>
void A::dosomething<0>()
{
  std::cout << "0 in A" << std::endl;
}

void A::show()
{
  dosomething<0>();
}

struct B : A {
  // Without the following declaration:
  // error: template-id ‘dosomething<1>’ for ‘void B::dosomething()’
  // does not match any template declaration
  template <int i>
  void dosomething();
};

template<>
void B::dosomething<1>()
{
  std::cout << "1 in B" << std::endl;
}

int main()
{
  A x;
  x.dosomething<0>();

  B y;
  y.dosomething<0>(); // Link error!
  y.show();
  y.dosomething<1>();

  return 0;
}

模板成员A::dosomething()在基类中显式专用于i=0。模板的代码是显式生成的,并在成员A::show()中调用。

我发现的第一个问题是:

A)没有重复的声明

template <int i>
void dosomething();

B的定义内,代码无法编译,并显示错误:

template-id ‘dosomething<1>’ for ‘void B::dosomething()’
does not match any template declaration.

为什么基类A中的先前声明不可见?

B)上面的代码引起了链接错误:

undefined reference to `void B::dosomething<0>()'

该错误是由于main中的调用y.dosomething<0>()引起的。可以通过调用y.A::dosomething<0>()来避免。为什么dosomething<0>()B的实例中显然不可见?

1 个答案:

答案 0 :(得分:3)

当您对成员函数进行out-of-line定义时,将在::运算符之前引用的类中查找该函数的声明。

考虑一下:

struct C { void test(); };
struct D : C { };

void D::test() { }; // error, test is not a member of D but of C

这与

template<> void B::dosomething<1>() 
{ }

dosomething及其所有专业化定义必须由声明其的类(即在A中声明的类)进行限定,就像对dosomething<0>所做的方式一样。

还要注意,dosomethingB的声明与A的声明完全无关。您由于调用未定义的专业化B::dosomething<0>而收到链接错误。

您可以创建特殊化template<> void A::dosomething<1>(){ },但是您并没有得到预期的多态行为,如果您确实需要A::dosomething<1>的不同版本,则所有派生类都将共享dosomething<1> {1}}受子类限制,您仅限于初始重复,并且为了从A::dosomething<0>访问B,您必须像static_cast<A&>(b).dosomething<0>()那样进行操作。

您还应该查看此answer

中的静态多态性