将“ typedef”从“ template”的基类传播到派生类

我试图定义基类,它只包含 typedef 的。

template<typename T>
class A
{
public:
typedef std::vector<T> Vec_t;
};




template<typename T>
class B : public A<T>
{
private:
Vec_t v;  // fails - Vec_t is not recognized
};

为什么在 B 中我收到一个错误,Vec _ t 不被识别,我需要显式地写它?

typename A<T>::Vec_t v;
32722 次浏览

因为编译器不能确定 Vec_t是否命名了一个类型。例如,A<T>可能是专门为 T=int没有具有特定的 typedef

您需要显式限定 Vec_t的使用,因为编译器不知道 Vec_t来自哪里。

它不能假定 A 的任何结构,因为类模板 A 可能是专门化的。专门化可能包括一个不是 typedef 的 Vec_t,或者它甚至可能根本不包括一个成员 Vec_t

Vec _ t 不是一个依赖名称,编译器需要知道它是什么,而不需要实例化任何模板(在本例中是基类)。实际上,这与下列情况没有什么不同:

template <class T>
class X
{
std::string s;
}

在这里,编译器也需要了解 std: : string,即使 X 没有实例化,因为名称不依赖于模板参数 T (编译器可以假设)。

总之,模板基类中的 typedef 对于派生类似乎没有什么用处。但是,typedef 对于用户是有用的。

对于模板,有一些名称叫做依赖名称和 非依赖性名称。

如果名称依赖于模板参数 T,那么它的 受供养人名称和其他不依赖于参数 T 的名称就是 独立名称。

规则是这样的: 编译器不会 查看依赖的基类(如 A)当查找非依赖性 名称(如 Vec _ t), 编译器甚至不知道它们 存在,更不用说是类型。

在知道 T之前,编译器不能假设 Vec_t是一种类型,因为 A<T>有一个潜在的专门化,其中 A<T>:: Vec_t是一个数据成员

所以解决方案是使用类型名

 typename A<T>::Vec_t v;  ← good

我建议你通过这个 https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types

旧(断)链接: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18

我认为这个问题是重复的,但我现在找不到它。C + + 标准表示,您应该根据14.6.2/3完全限定 name:

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

UPD: 我终于找到了复制品: 找到了

这个概念可以与我们如何使用 std::vector<T>联系起来。例如,如果我们有一个 std::vector<int> Foo。现在,我们决定使用它的任何成员类型,比如 iterator。在这个场景中,我们明确提到

std::vector<int>::iterator foo_iterator;

在您的示例中,类似地,为了使用 template <typename T> class A的公共成员类型 Vec_t,您需要将其显式声明为

A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;

为了完整起见,以下是一些减轻这种麻烦的方法:

  • 在派生类中重新类型定义这些类型,或者更好的方法是 方法 -
  • 只需用 using declaration导入派生类作用域中的这些名称:

template<typename T>
class A
{
public:
typedef std::vector<T> Vec_t;
};




template<typename T>
class B : public A<T>
{
public:
using typename A<T>::Vec_t;
// .........


private:
Vec_t v;
};

如果在派生类中不止一次提到继承的 typedef,那么它将非常有用。也不需要每次都添加 typename