如果两个类都是模板,为什么我不能简单地使用基类中定义的类型?

se0*_*808 5 c++ inheritance templates

如果两个类都是模板,为什么我不能简单地使用基类中定义的类型?是否有一些关于搜索模板成员的规则?这是我能推断出的最简单的例子:

struct iA {
    using type = int;
};
template <class T> struct tA {
    using type = T;
};

struct iB1 : iA {
    void f(type i) {}
};
struct iB2 : tA<int> {
    void f(type i) {}
};
template <class T> struct tB1 : iA {
    void f(type i) {}
};
template <class T> struct tB2 : tA<int> {
    void f(type i) {}
};
template <class T> struct tB3 : tA<T> {
    // void f(type i) {} // error: 'type' has not been declared
    void f(typename tA<T>::type i) {}
};

int main() {}
Run Code Online (Sandbox Code Playgroud)

当然,我可以添加typename tA<T>::,但是有更优雅的解决方案吗?

Col*_*mbo 5

问题是基类是依赖的,因此只有在我们查找依赖名称时才会检查它的范围。[温度.dep]/3:

在类或类模板的定义中,如果基类依赖于模板参数在类模板或成员的定义点或实例化过程中的非限定名称查找期间不会检查基类范围类模板或成员。

这条规则的原因是可能有例如基类模板的特化。由于我们在定义时不知道特定的模板参数,因此我们无法检查基类范围。

type不依赖,因此不会在依赖库中查找tA<T>。但是,因为它不依赖,所以它的声明必须在定义时可用,[temp.res]/10:

如果名称不依赖于模板参数(如 14.6.2 中所定义),则该名称的声明(或声明集)应在名称出现在模板定义中的点的范围内;该名称绑定到在该点找到的声明(或多个声明),并且此绑定不受在实例化点可见的声明的影响。


如果需要type在派生类中频繁使用,using声明会有所帮助。

template <class T> struct tB3 : tA<T> {
    using typename tA<T>::type;
    void f(type i) {}
};
Run Code Online (Sandbox Code Playgroud)

演示