将“typedef”从“模板”的基类传播到派生类
-
10-07-2019 - |
题
我正在尝试定义仅包含 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;
解决方案
我认为这个问题是重复的,但我现在找不到了。 C ++标准说你应该根据14.6.2 / 3完全限定名称:
在类模板的定义或类模板的成员中,如果类模板的基类依赖于模板参数,则在非限定名称查找期间不检查基类范围在类模板或成员的定义点或在类模板或成员的实例化期间。
UPD:我最终发现重复:这里是。
其他提示
在模板的情况下,存在称为依赖和非依赖名称的内容。
如果name依赖于模板参数T,其依赖名称和其他不依赖于参数T的名称是独立的名称。
这是规则:编译器没有 查看依赖基类(如 A)在查找不依赖时 名字(如Vec_t)。结果是, 编译器甚至不知道它们 存在,更不用说是类型。
编译器不能认为Vec_t
是一种类型,直到它知道T
,因为A<T>
有潜在的专业化,其中A<T>:: Vec_t
是一个数据成员
所以解决方案是使用typename
typename A<T>::Vec_t v; ← good
我建议你仔细阅读 https://isocpp.org/维基/常见问题/模板#非依赖名的查找类型的。
旧(破碎)链接: http:// www。 parashift.com/c++-faq-lite/templates.html#faq-35.18
因为编译器不确定Vec_t
命名一个类型。例如,A<T>
可能专门用于T=int
而不是具有该特定的typedef
。
为了完整起见,您可以通过以下方法稍微减轻这种麻烦:
- 在派生的类中重新类型的这些类型,或者更好 - 与方法一样 -
- 只需使用以下命令将这些名称导入派生类作用域中
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
每次都这样。
您需要明确限定Vec_t
的使用,因为编译器不知道<=>来自何处。
它不能假设A的结构,因为类模板A可能是专用的。专业化可能包括<=>,它不是typedef,或者根本不包括成员<=>。
Vec_t不是依赖名称,编译器需要知道它是什么而不实例化任何模板(在这种情况下是基类)。它真的没有什么不同:
template <class T>
class X
{
std::string s;
}
这里编译器需要知道std :: string,即使X没有实例化,因为名称不依赖于模板参数T(就编译器而言)。
总而言之,模板基类中的typedef在派生类中使用似乎毫无用处。但是,typedef对用户很有用。
这个概念可以与我们如何使用std::vector<T>
相关联。例如,如果我们有std::vector<int> Foo
。现在,我们决定使用它的任何成员类型,比如说iterator
。在这种情况下,我们明确提到
std::vector<int>::iterator foo_iterator;
同样在您的情况下,为了使用公共成员类型Vec_t
of template <typename T> class A
,您需要明确声明它为
A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;