在派生类中专门化模板成员
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<0>()
造成的。可以通过调用y.A::dosomething<0>()
来避免这种情况。为什么dosomething<0>()
在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<0>
所做的那样。
还要注意B
中dosomething
的声明与A
的声明完全无关。由于调用了未定义的专业化B::dosomething<0>
,您收到了链接错误。
您可以创建特化 template<> void A::dosomething<1>()
,但您没有得到您期望的多态行为,如果您确实需要不同版本的 dosomething<1>
子类,A::dosomething<1>
将由所有派生类共享,您仅限于最初的重复,为了从B
访问A::dosomething<0>
,您可以使用static_cast<A&>(b).dosomething<0>()
。
你还应该看看这个answer中的静态多态性
【讨论】:
感谢您的回答。但是我仍然对B
没有看到A
的模板声明这一事实感到困惑,因此我无法进一步专门化模板函数A::dosomething
@francesco 我编辑了答案以提供更多澄清,如果还有其他需要澄清的地方,请告诉我
非常感谢您的澄清和链接。以上是关于在派生类中专门化模板成员的主要内容,如果未能解决你的问题,请参考以下文章