依赖范围和嵌套模板
当我编译这个时:
#ifndef BTREE_H
#define BTREE_H
#include <QList>
template <class T, int degree>
class btree
{
public:
class node
{
public :
node();
private:
node* parent;
QList<T> values;
QList<node*> children;
};
public:
btree();
void insert(const T& value);
node* findLeaf(const T& value);
void performInsertion(const T& value, node& place);
//
node* root;
};
#endif // BTREE_H
findLeaf 的实现是这样的:
template <class T, int degree>
btree<T,degree>::node* btree<T,degree>::findLeaf(const T &value)
{
if(root == NULL)
return root;
}
出现此错误:
error: need ‘typename’ before ‘btree<T, degree>::Node’
because ‘btree<T, degree>’ is a dependent scope
When I compile this:
#ifndef BTREE_H
#define BTREE_H
#include <QList>
template <class T, int degree>
class btree
{
public:
class node
{
public :
node();
private:
node* parent;
QList<T> values;
QList<node*> children;
};
public:
btree();
void insert(const T& value);
node* findLeaf(const T& value);
void performInsertion(const T& value, node& place);
//
node* root;
};
#endif // BTREE_H
Implementation of findLeaf is this:
template <class T, int degree>
btree<T,degree>::node* btree<T,degree>::findLeaf(const T &value)
{
if(root == NULL)
return root;
}
This error occurs:
error: need ‘typename’ before ‘btree<T, degree>::Node’
because ‘btree<T, degree>’ is a dependent scope
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,这与 C++ 的语法无关,而是与 C++ 模板的延迟实例化有关
和两阶段查找。
在 C++ 中,从属名称是一个名称或符号,其含义取决于一个或多个
模板参数:
通过单独解析该代码片段,在不知道 T 的所有未来值的情况下,任何 C++ 编译器都无法推断出
T
中的frob
是否是函数名称、类型名称等否则,或者它是否存在。为了说明为什么这是相关的,想象一下您将替换 T 的某些类型:
将它们放入我们的 Foo 模板中:
与此相关的是两阶段查找的概念。在第一阶段,
解析和编译非依赖代码:
第一阶段让编译器在模板定义本身中发出错误消息。
第二阶段将触发模板与当时已知的类型 T 相关的错误。
一些早期的 C++ 编译器只会在实例化模板后才解析它们;对于这些编译器,不需要消除歧义,因为在实例化时,模板参数是已知的。这种单阶段查找的问题是,模板本身中的许多错误根本不会被检测到,或者只能在编译后期检测到,因为模板默认情况下是延迟实例化的,即仅实例化模板的一部分。类模板被扩展为实际使用的,此外它还为您提供了更多可能源于模板参数的神秘错误消息。
因此,为了使两阶段查找起作用,您必须帮助编译器。
在这种情况下,您必须使用
typename
来告诉编译器您指的是类型:编译器现在知道 x 是 Flob 类型的变量:)
No, this has not to do with C++'s grammar, but with lazy instantiation of C++ templates
and two phase lookup.
In C++, a dependent name is a name or symbol whose meaning depends on one or more
template parameters:
By parsing that snippet alone, without knowin all future values of T, no C++ compiler can deduce whether
frob
inT
is a function name, a type name, something else, or whether it exists at all.To give an example for why this is relevant, imagine some types you will substitute for T:
Put those into our Foo-template:
Relevant in this is the concept of two-phase lookup. In the first phase,
non-dependent code is parsed and compiled:
This first phase is what lets compilers emit error messages in the template definition itself.
The second phase would trigger errors of your template in conjunction with the then-known type T.
Some early C++ compilers would only parse templates once you instantiate them; with those compilers, disambiguation wasn't needed, because at the point of instantiation, the template arguments are known. The problem with this one-phase lookup is that many errors in the template itself won't be detected at all or only late in the compile, because templates are by default instantiated lazily, i.e. only parts of a class-template are expanded that are actually used, plus it gives you more cryptic error messages that possibly root in the template-argument.
So in order for two-phase lookup to work, you must help the compiler.
In this case, you must use
typename
in order to tell the compiler that you mean a type:The compiler now knows that x is a variable of type Frob :)
C++ 语法非常糟糕,因此,当给定模板类时,不可能知道您引用的
::node
是变量/常量还是类型。因此,该标准要求您在类型之前使用
typename
来消除这种歧义,并将所有其他用法视为变量。这
就是定义的正确签名。
The C++ grammar is horrendous, and as such it is not possible, when given a template class, to know whether the
::node
you refer to is a variable/constant or a type.The Standard therefore mandates that you use
typename
before types to remove this ambiguity, and treats all other usages as if it was a variable.Thus
is the correct signature for the definition.