以下是代码和引用来自Addison Wesley的 C ++模板:
template <typename T>
class MyClass {
typename T::SubType * ptr;
…
};
如果没有typename,SubType将被视为静态成员。因此,它将是一个具体的变量或对象。因此,表达式
T::SubType *ptr
将是类T的静态SubType成员与ptr的乘法。
现在当我编译没有关键字'typename'的代码时,我得到的错误是:type ‘T’ is not derived from type ‘MyClass<T>’
。
编译器是否识别'T'? 如果没有,那么它不应该是未定义的引用错误吗? 如果是,那为什么这是一个错误?
好的,这是完整的代码:
#include <iostream>
#include <vector>
template <typename T> class MyClass
{
T::SubType * ptr;
};
int main ()
{
return 0;
}
我得到的错误是:
~/Desktop/notes **g++ templates/programs/trial.cpp**
templates/programs/trial.cpp:6: error: type ‘T’ is not derived from type ‘MyClass<T>’
templates/programs/trial.cpp:6: error: expected ‘;’ before ‘*’ token
答案 0 :(得分:3)
这是从g ++中获得相同错误的另一种方法:
class Foo { static const int x = 0;};
template <typename T> class MyClass
{
Foo::x * ptr;
};
和另一个:
class Foo { static const int x = 0;};
class MyClass
{
Foo::x * ptr;
};
但是你得到了一个不同的错误:
// class Foo { static const int x = 0;};
template <typename T> class MyClass
{
Foo::x * ptr;
};
所以:
因为T是依赖类型,所以g ++假定T::SubType
是将在第二阶段查找发生时定义的对象。这是预期的,这是typename
在这里需要的常见原因。
即使 T::SubType
存在并且是一个对象,代码仍然很糟糕,就像Foo::x *ptr
存在Foo::x
时一样糟糕一个东西。我仍然不明白错误消息的内容 - Foo
如何从MyClass
派生出来?但错误消息与模板无关。
“未定义的引用”是链接器错误。由于此代码甚至无法编译,因此您不应期望在任何地方看到“对T的未定义引用”。
到目前为止,我还没有看到Foo
如何从MyClass
派生出来。我尝试了以下内容,看看它是否能提供原始消息含义的线索,但它失败了,因为MyClass
是一个不完整的类型,它没有告诉我任何关于{{1}会发生什么的事情。来自Foo
:
MyClass
Comeau为所有这些情况提供了更明智的错误消息 - 没有关于派生类型的信息,只是说class MyClass
{
class Foo: public MyClass { static const int x = 0;};
Foo::x * ptr;
};
不是类型。因此,解释g ++的错误信息将采取关于g ++内部的知识或良好猜测,并且在尝试解析类模板的过程中它最终放弃了。
答案 1 :(得分:2)
如果没有typename,SubType将被视为静态成员。因此,它将是一个具体的变量或对象。因此,表达式T :: SubType * ptr将是类T的静态SubType成员与ptr的乘法。
当应用于您给出的示例时,此描述不正确。在类体中,不能有表达式,也不会将构造解析为乘法。但是,在C ++ 03语法中,有一个看起来如下的构造
struct Base { int a; };
struct Derived : Base {
Base::a; // access-declaration
};
此构造在C ++ 03中已弃用但仍受支持,并且与以下内容相同
struct Base { int a; };
struct Derived : Base {
using Base::a; // using-declaration
};
因为您没有告诉编译器T::SubType
是一个类型,因此告诉编译器它应该将它解析为指针声明的类型,编译器假定T::SubType
是名称在访问声明中。因此,它预期在它之后直接使用分号,因此它期望T
是MyClass<T>
的基类(或者MyClass<T>
是派生的T
)的类。错误消息实际上是向后的:
if (! UNIQUELY_DERIVED_FROM_P (IDENTIFIER_TYPE_VALUE (cname),
ctype))
{
cp_error ("type `%T' is not derived from type `%T'",
IDENTIFIER_TYPE_VALUE (cname), ctype);
...
}
虽然宏说
/* Nonzero iff TYPE is uniquely derived from PARENT. Under MI, PARENT can
be an ambiguous base class of TYPE, and this macro will be false. */
#define UNIQUELY_DERIVED_FROM_P(PARENT, TYPE) ...
答案 2 :(得分:0)
由于T::SubType
是从属名称,因此您需要通过键入SubType
告诉编译器typename
是类型(不是静态数据成员)关键字。
在此处阅读依赖名称:
编辑:
关于你的问题(你在评论中重复):
我认为你发布的不是完整的代码。所以我无法对此作出具体评论。此外,有时编译器不够智能,无法准确地指出模板代码中的错误。所以我建议你阅读有关依赖名称和何时&amp;为什么typename
是必需的。希望在那之后你不会有任何问题!