我正在尝试定义基类,它只包含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;
答案 0 :(得分:43)
我认为这个问题是重复的,但我现在找不到了。 C ++标准说你应该根据14.6.2 / 3完全限定名称:
在类模板的定义或类模板的成员中,如果类模板的基类依赖于模板参数,则在非限定名称查找期间不检查基类范围在类模板或成员的定义点或在类模板或成员的实例化期间。
UPD:我终于找到了重复:here it is。
答案 1 :(得分:33)
在模板的情况下,存在称为依赖和非依赖名称的内容。
如果name依赖于模板参数T,其依赖名称和其他不依赖于参数T的名称是独立的名称。
这是规则:编译器没有 查看依赖基类(如 A)在查找不依赖时 名字(如Vec_t)。结果是, 编译器甚至不知道它们 存在,更不用说是类型。
编译器不能认为Vec_t
是一种类型,直到它知道T
,因为A<T>
存在A<T>:: Vec_t
的潜在专长,其中 typename A<T>::Vec_t v; ← good
是a是数据成员
所以解决方案是使用typename
{{1}}
我建议您完成此https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types。
旧(破碎)链接:http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18
答案 2 :(得分:7)
因为编译器不确定Vec_t
是否为某个类型命名。例如,A<T>
可能专门针对T=int
而非具有该特定typedef
。
答案 3 :(得分:3)
出于完整性考虑,您可以通过以下两种方法来减轻这种麻烦:
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
。
答案 4 :(得分:2)
您需要明确限定Vec_t
的使用,因为编译器不知道Vec_t
的来源。
它不能假设A的结构,因为类模板A可能是专用的。专业化可能包括Vec_t
,它不是typedef,或者根本不包含成员Vec_t
。
答案 5 :(得分:1)
Vec_t不是依赖名称,编译器需要知道它是什么而不实例化任何模板(在这种情况下是基类)。它真的没有什么不同:
template <class T>
class X
{
std::string s;
}
这里编译器需要知道std :: string,即使X没有实例化,因为名称不依赖于模板参数T(就编译器而言)。
总而言之,模板基类中的typedef在派生类中使用似乎毫无用处。但是,typedef对用户很有用。
答案 6 :(得分:1)
这个概念可以与我们如何使用std::vector<T>
相关联。例如,如果我们有std::vector<int> Foo
。现在,我们决定使用它的任何成员类型,比如说iterator
。在这种情况下,我们明确提到
std::vector<int>::iterator foo_iterator;
同样在您的情况下,为了使用Vec_t
的公共成员类型template <typename T> class A
,您需要明确声明它为
A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;