将“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;很好。不需要我相信这个问题是重复的,但我现在找不到。 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<T>
有一个潜在的特化,其中A<T>:: 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<T>
可能专门用于T=int
,而不具有特定的typedef
。
【讨论】:
对于T
类型变量,A<T>
只是前向声明,它没有定义。只有A<t>
其中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<T>::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<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;
【讨论】:
以上是关于将“typedef”从“模板”的基类传播到派生类的主要内容,如果未能解决你的问题,请参考以下文章