依赖范围和嵌套模板

发布于 2024-11-18 12:23:18 字数 897 浏览 2 评论 0原文

当我编译这个时:

#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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

吻安 2024-11-25 12:23:18

不,这与 C++ 的语法无关,而是与 C++ 模板的延迟实例化有关
和两阶段查找。


在 C++ 中,从属名称是一个名称或符号,其含义取决于一个或多个
模板参数:

template <typename T>
struct Foo {
    Foo () {
        const int x = 42;
        T::Frob (x);
    }
};

通过单独解析该代码片段,在不知道 T 的所有未来值的情况下,任何 C++ 编译器都无法推断出 T 中的 frob 是否是函数名称、类型名称等否则,或者它是否存在。

为了说明为什么这是相关的,想象一下您将替换 T 的某些类型:

struct Vietnam {
    typedef bool Frob; // Frob is the name of a type alias
};    

struct Football {
    void Frob (int) {} // Frob is a function name
};

struct BigVoid {};     // no Frob at all!

将它们放入我们的 Foo 模板中:

int main () {
    Foo<Vietnam> fv;   // Foo::Foo would declare a type
    Foo<Football> ff;  // Foo::Foo would make a function call
    Foo<BigVoid> fbv;  // Foo::Foo is not defined at all
}

与此相关的是两阶段查找的概念。在第一阶段,
解析和编译非依赖代码:

template <typename T>
struct Foo {
    Foo () {
        const int x = 42; // does not depend on T
        T::Frob (x);      // full check skipped for second phase, only rudimentary checking
    }
};

第一阶段让编译器在模板定义本身中发出错误消息。

第二阶段将触发模板与当时已知的类型 T 相关的错误。

一些早期的 C++ 编译器只会在实例化模板后才解析它们;对于这些编译器,不需要消除歧义,因为在实例化时,模板参数是已知的。这种单阶段查找的问题是,模板本身中的许多错误根本不会被检测到,或者只能在编译后期检测到,因为模板默认情况下是延迟实例化的,即仅实例化模板的一部分。类模板被扩展为实际使用的,此外它还为您提供了更多可能源于模板参数的神秘错误消息。

因此,为了使两阶段查找起作用,您必须帮助编译器。
在这种情况下,您必须使用 typename 来告诉编译器您指的是类型:

template <typename T>
struct Foo {
    Foo () {
        const int x = 42;
        typename T::Frob (x);
    }
};

编译器现在知道 x 是 Fl​​ob 类型的变量:)

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:

template <typename T>
struct Foo {
    Foo () {
        const int x = 42;
        T::Frob (x);
    }
};

By parsing that snippet alone, without knowin all future values of T, no C++ compiler can deduce whether frob in T 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:

struct Vietnam {
    typedef bool Frob; // Frob is the name of a type alias
};    

struct Football {
    void Frob (int) {} // Frob is a function name
};

struct BigVoid {};     // no Frob at all!

Put those into our Foo-template:

int main () {
    Foo<Vietnam> fv;   // Foo::Foo would declare a type
    Foo<Football> ff;  // Foo::Foo would make a function call
    Foo<BigVoid> fbv;  // Foo::Foo is not defined at all
}

Relevant in this is the concept of two-phase lookup. In the first phase,
non-dependent code is parsed and compiled:

template <typename T>
struct Foo {
    Foo () {
        const int x = 42; // does not depend on T
        T::Frob (x);      // full check skipped for second phase, only rudimentary checking
    }
};

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:

template <typename T>
struct Foo {
    Foo () {
        const int x = 42;
        typename T::Frob (x);
    }
};

The compiler now knows that x is a variable of type Frob :)

-残月青衣踏尘吟 2024-11-25 12:23:18

C++ 语法非常糟糕,因此,当给定模板类时,不可能知道您引用的 ::node 是变量/常量还是类型。

因此,该标准要求您在类型之前使用 typename 来消除这种歧义,并将所有其他用法视为变量。

template <typename T, int degree>
typename btree<T,degree>::node* btree<T,degree>::findLead(T const& value)
^~~~~~~~

就是定义的正确签名。

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

template <typename T, int degree>
typename btree<T,degree>::node* btree<T,degree>::findLead(T const& value)
^~~~~~~~

is the correct signature for the definition.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文