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

Posted

技术标签:

【中文标题】将“typedef”从“模板”的基类传播到派生类【英文标题】:Propagating 'typedef' from based to derived class for 'template' 【发布时间】:2010-12-11 05:04:46 【问题描述】:

我正在尝试定义仅包含 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;

【问题讨论】:

完全重复:***.com/questions/1567730/… 好吧,实际上并不是完全重复,因为您提到的帖子谈论的是一种方法,而这篇谈论的是一种类型。 类型名 A::Vec_t v;很好。不需要 那里 【参考方案1】:

我相信这个问题是重复的,但我现在找不到。 C++ 标准说你应该根据 14.6.2/3 完全限定名称:

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

UPD:我终于找到了重复:here it is。

【讨论】:

顺便说一句,我总是觉得我必须“重新定义”所有内容......这不愉快,一点也不愉快。 顺便说一句,在限定条件下,您不需要所有模板参数。因为注入了类名,写typename B::Vec_t就够了 @JohannesSchaub-litb 我正在尝试按照您所说的进行操作,但是如果我没有为 B 指定模板参数,则会出现错误。(B 不是类,命名空间,或枚举) @GonzaloSolera 我遇到了与您相同的错误结果,但仅在我的一个平台上,一个具有较旧的 C++ 标准的平台上。我想知道完全合格的需求是否在某个时候发生了变化?【参考方案2】:

在模板的情况下,有一些称为依赖和非依赖的名称。

如果名称依赖于模板参数T,则它的依赖名称和其他不依赖于参数T的独立名称。

规则如下:编译器不会 查看依赖基类(如 A) 查找非依赖项时 名称(如 Vec_t)。因此, 编译器甚至不知道他们 更不用说类型了。

编译器在知道T 之前不能假定Vec_t 是一个类型,因为A&lt;T&gt; 有一个潜在的特化,其中A&lt;T&gt;:: Vec_t 是一个数据成员

所以解决方案是使用 typename

 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

【讨论】:

您的答案似乎除了解释之外还提供了解决方案。谢谢。 如果您通知我您已更正链接,我会为您提供 +1。【参考方案3】:

因为编译器不确定Vec_t 是否命名了一个类型。例如,A&lt;T&gt; 可能专门用于T=int,而具有特定的typedef

【讨论】:

对于T 类型变量,A&lt;T&gt; 只是前向声明,它没有定义。只有A&lt;t&gt; 其中t 是一个类型(不是类型变量)可以被定义(通过特化模板定义或通过显式特化)。 IOW,即使您从 C++ 中删除了模板显式和部分特化(但没有更改任何其他内容),它仍然是不正确的。【参考方案4】:

为了完整起见,以下是您可以稍微减轻这种麻烦的方法:

重新定义派生类中的那些类型,或者更好 - 与 方法 - 只需在派生类范围内使用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

【讨论】:

你有一个错字。 using typename A::Vec_t; 应该是 using typename A&lt;T&gt;::Vec_t;【参考方案5】:

您需要明确限定Vec_t 的使用,因为编译器不知道Vec_t 的来源。

它不能假设任何关于 A 的结构,因为类模板 A 可能是特化的。专业化可能包括不是 typedef 的 Vec_t,或者它甚至可能根本不包括成员 Vec_t

【讨论】:

【参考方案6】:

Vec_t 不是依赖名称,编译器需要知道它是什么而不实例化任何模板(在本例中为基类)。真的和:

template <class T>
class X

    std::string s;

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

总而言之,模板基类中的 typedef 在派生类中使用似乎毫无用处。然而,typedef 对用户很有用。

【讨论】:

这里是class X : T 吗?【参考方案7】:

这个概念可能与我们如何使用std::vector&lt;T&gt; 相关联。例如,如果我们有一个std::vector&lt;int&gt; Foo。现在,我们决定使用它的任何成员类型,比如说iterator。在这种情况下,我们明确提到

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

在您的情况下,为了使用template &lt;typename T&gt; class A 的公共成员类型Vec_t,您需要将其显式声明为

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

【讨论】:

以上是关于将“typedef”从“模板”的基类传播到派生类的主要内容,如果未能解决你的问题,请参考以下文章

包含指向派生模板类的基类指针的类的赋值运算符和复制构造函数

派生类中隐藏的基类模板成员函数,尽管参数列表不同

如何使用 C++ 中的模板编程从基类创建派生类?

在派生类中专门化模板成员

继承中的基类是不是复制到派生类?

是否可以使用“this”从派生对象的基类发出信号