模板特化和从其他模板类继承模板类
Posted
技术标签:
【中文标题】模板特化和从其他模板类继承模板类【英文标题】:Template specialization and inheritance template class from other template class 【发布时间】:2019-05-29 20:39:17 【问题描述】:我对下一个代码有一些疑问:
template<typename T>
class Base;
template<typename T, typename P>
class Base<T(P)>
;
template<typename T>
class Derived;
template<typename T, typename P>
class Derived<T(P)> : public Base<T(P)>
;
类特化Derived<T(P)>
继承自类template<typename T> class Base
还是继承自类template<typename T, typename P> class Base<T(P)>
?
当我将类专业化Derived<T(P)>
的模板参数T
和P
与class Base
的模板参数T
绑定时,名称是什么。
【问题讨论】:
【参考方案1】:类特化
Derived<T(P)>
继承自类template<typename T> class Base
还是从类template<typename T, typename P> class Base<T(P)>
?
从技术上讲,两者都不是。类或类模板从不从模板继承,仅从一种特定的基类类型继承。即Derived<int(float&)>
继承Base<int(float&)>
,以此类推。对于这些特定类型,该基类从与 Base
关联的最专门的声明中实例化。如果有额外的部分特化或显式特化,那么这种区别的重要性就会显现出来。
如果我稍微改变一下你的例子,
template<typename T> // #1
class Base;
template<typename T, typename P> // #2
class Base<T(P)>
public:
static const int mem1 = 1;
;
template<typename T>
class Derived;
template<typename T, typename P>
class Derived<T(P)> : public Base<T(P)>
;
class SomethingElse ;
template<typename P> // #3
class Base<SomethingElse(const P&)>
public:
static const long long mem2 = 2;
;
using ThingType = Derived<SomethingElse(const std::string&)>;
const auto A = ThingType::mem1; // Error!
const auto B = ThingType::mem2; // OK
说部分特化Derived<T(P)>
继承部分特化Base<T(P)>
是不正确的,因为示例类型Derived<SomethingElse(const std::string&)>
使用了Derived
部分特化,但根本没有使用Base
部分特化。 Base<T(P)>
仅表示名为Base
的模板,无论Base
的专业化定义与模板参数T(P)
最匹配。当 Derived
的每个特化被实例化时,关于基类 Base<T(P)>
的含义的决定是针对每个特定的模板参数集独立做出的。
当我将类专业化
Derived<T(P)>
的模板参数T
和P
与Base 类的模板参数T
绑定时,它的名称是什么。
除了您使用的是依赖复合类型之外,我不知道任何术语。 (Dependent = 依赖于一个或多个模板参数;Compound = T(P)
类型涉及其他类型T
和P
。)这也使得Base<T(P)>
成为Derived<T(P)>
定义中的依赖基类,意思是编译器不会在那里寻找普通标识符,您需要使用this->name
或Base::name
使这些名称有效。模板参数在专业化模板参数中的“可推导上下文”中也很重要。
【讨论】:
为什么这么难?我正在写论文,我找不到这种结构的精确定义和解释。 @DarkHell 我仍然不确定你想要一个术语是什么。 我以为这样的现象是有术语的。 我第一次遇到像 BaseT(P)
这里是一个函数类型。如果我们有函数int f(double);
,那么Base<decltype(f)>
与Base<int(double)>
相同,并且该类型将通过推导T=int
和P=double
来使用偏特化。【参考方案2】:
从模板Derived<T(P)>
实例化的类继承自Base<T(P)>
实例化的类。由于T(P)
类型与您的Base
部分特化匹配,因此该模板将用于实例化要继承的类。
它只是称为继承。那里没有什么特别的。您只是用 T(P)
类型实例化模板 Base
并从结果类继承。
Base<T(P)>
将在 Derived<T(P)>
被实例化时被实例化,因此 Derived<void(int)>
继承自 Base<void(int)>
。这两个实例化都将通过相同的规则集来确定使用哪个模板来实例化该类。
您可能会感到困惑,认为T(P)
是一些特殊的模板。它不是。它只是类型“返回T
并接受P
类型的单个参数的函数”。当然,像这样的类型在模板之外并没有出现太多,但它们在其他地方是完全合法的。即
using FuncType = void(int);
// These two declarations are exactly the same
void doAThing(FuncType* callback);
void doAThing(void(*callback)(int));
【讨论】:
以上是关于模板特化和从其他模板类继承模板类的主要内容,如果未能解决你的问题,请参考以下文章
C++模板编程中只特化模板类的一个成员函数(花样特化一个成员函数)
C++模板类模板的全部特例化和局部特例化(偏特化-partial specialization)