在派生类中专门化模板成员

Posted

技术标签:

【中文标题】在派生类中专门化模板成员【英文标题】:specialize template member in derived class 【发布时间】:2018-11-05 20:53:31 【问题描述】:

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

这是一个最小的例子来说明我遇到的问题。

#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&lt;0&gt;() 造成的。可以通过调用y.A::dosomething&lt;0&gt;() 来避免这种情况。为什么dosomething&lt;0&gt;()B 的实例中显然不可见?

【问题讨论】:

【参考方案1】:

当您对成员函数进行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&lt;0&gt; 所做的那样。

还要注意Bdosomething 的声明与A 的声明完全无关。由于调用了未定义的专业化B::dosomething&lt;0&gt;,您收到了链接错误。

您可以创建特化 template&lt;&gt; void A::dosomething&lt;1&gt;() ,但您没有得到您期望的多态行为,如果您确实需要不同版本的 dosomething&lt;1&gt; 子类,A::dosomething&lt;1&gt; 将由所有派生类共享,您仅限于最初的重复,为了从B 访问A::dosomething&lt;0&gt;,您可以使用static_cast&lt;A&amp;&gt;(b).dosomething&lt;0&gt;()

你还应该看看这个answer中的静态多态性

【讨论】:

感谢您的回答。但是我仍然对B 没有看到A 的模板声明这一事实感到困惑,因此我无法进一步专门化模板函数A::dosomething @francesco 我编辑了答案以提供更多澄清,如果还有其他需要澄清的地方,请告诉我 非常感谢您的澄清和链接。

以上是关于在派生类中专门化模板成员的主要内容,如果未能解决你的问题,请参考以下文章

在模板派生类中,为啥我需要在成员函数中使用“this->”来限定基类成员名称?

派生类中隐藏的基类模板成员函数,尽管参数列表不同

在派生类中无法访问受保护的成员

在派生类中无法访问受保护的成员?

在派生类中使用模板基类模板构造函数

c++继承是如何工作的?