模板专业化和继承模板类

时间:2019-05-29 20:39:18

标签: c++ templates inheritance specialization

我对下一个代码有疑问:

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)> {

};
  1. 类专业化Derived<T(P)>是从类template<typename T> class Base还是类template<typename T, typename P> class Base<T(P)>继承的?

  2. 当我将类专业化T的模板参数PDerived<T(P)>T的模板参数class Base绑定在一起时的名称是什么

2 个答案:

答案 0 :(得分:2)

  1. 从模板2实例化的类继承自add实例化的类。由于类型Derived<T(P)>与您的Base<T(P)>部分专业化匹配,因此该模板将用于实例化要继承的类。

  2. 这就是所谓的继承。那里没有什么特别的事情。您只需实例化类型为T(P)的模板Base并从结果类中继承。


Base将在T(P)实例化时被实例化,因此Base<T(P)>Derived<T(P)>继承。这两个实例都将遵循相同的规则集,以找出用于实例化该类的模板。

您可能会感到困惑,认为Derived<void(int)>是一些特殊的模板。它不是。它只是类型“返回Base<void(int)>并接受类型为T(P)的单个参数的函数”。当然,类似的类型在模板之外不会出现太多,但是在其他地方它们是完全合法的。即

T

答案 1 :(得分:2)

  
      
  1. 类专业化Derived<T(P)>是从类template<typename T> class Base还是类template<typename T, typename P> class Base<T(P)>继承的?
  2.   

从技术上讲,两者都不是。类或类模板永远不会从模板继承,而只能从一种特定的基类类型继承。也就是说,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)最匹配。实例化Base<T(P)>的每个特化后,将针对每个特定的模板参数集独立地决定基类Derived的含义。

  
      
  1. 我将类特化T的模板参数PDerived<T(P)>与Base类的模板参数T绑定时的名称是什么。
  2.   

除了您使用从属化合物类型之外,我对此一无所知。 (Dependent =取决于一个或多个模板参数; Compound =类型T(P)涉及其他类型TP。)这也使Base<T(P)>Derived<T(P)>的定义,这意味着编译器将不会在此处查找普通标识符,并且您需要使用this->nameBase::name来使这些名称有效。同样重要的是,模板参数应位于专业化模板参数中的“可推断上下文”中。