以下是代码和引用来自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
3 回答
这是从g获得相同错误的另一种方法:
另一个:
但是你得到了一个不同的错误:
所以:
因为T是从属类型,g假定
T::SubType
是将在第二阶段查找发生时定义的对象 . 这是预期的,这是通常的原因,这里需要typename
.即使
T::SubType
存在并且是一个对象,代码仍然很糟糕,就像Foo::x *ptr
存在Foo::x
并且是一个对象时一样 . 我仍然不明白错误信息是什么 - 如何从MyClass
派生Foo
会有什么帮助?但错误消息与模板无关 .“未定义的引用”是链接器错误 . 由于此代码甚至无法编译,因此您不应期望在任何地方看到“未定义的T引用” .
我到目前为止还没看到
Foo
甚至可以从MyClass
派生出来 . 我尝试了以下内容,看看它是否会提供原始消息的含义的线索,但它失败了因为MyClass
是一个不完整的类型,它没有告诉我如果Foo
是从MyClass
派生的将会发生什么:Comeau为所有这些案例提供了更明智的错误消息 - 没有任何关于派生类型的信息,只是说
T::SubType
isn 't a type. So explaining g++'的错误信息将会对g内部结构采取任何知识或良好猜测,并确切地说在尝试解析你的内容的过程中它终于放弃了类模板 .应用于您提供的示例时,此描述不正确 . 在类体中,不能有表达式,也不会将构造解析为乘法 . 但是,在C 03语法中,有一个结构如下所示
此构造在C 03中已弃用但仍受支持,并且与以下内容相同
因为您没有告诉编译器
T::SubType
是一个类型,因此告诉编译器它应该将其解析为指针声明的类型,编译器假定T::SubType
是访问声明中的名称 . 因此它预期在它之后直接有一个分号,因此它期望T
是MyClass<T>
的基类(或者MyClass<T>
是T
的派生类) . 错误消息实际上是向后的:虽然宏说
因为
T::SubType
是从属名称,所以您需要通过键入typename
keyword告诉编译器SubType
是一个类型(不是静态数据成员) .在此处阅读依赖名称:
Name binding and dependent names (C++ only)
Dependent Names(向下滚动并阅读本节 - 如果您阅读完整文章会更好)
编辑:
至于你的问题(你在评论中重复):
我认为你足够聪明,可以准确地指出模板代码中的错误 . 所以我建议你阅读有关依赖名称以及何时以及为何需要
typename
. 希望在那之后你不会有任何问题!