如下一个模板类:
template <class T>
class CTest
{
public:
typedef map<int, T> TEMPLATE_MAP;
typedef map<int, T>::iterator TEMPLATE_MAP_ITER;
};
表面上看去没有问题,实际编译的时候会发现问题:
------ Build started: Project: typename, Configuration: Debug Win32 ------
Compiling...
main.cpp
e:\My Documents\Visual Studio Projects\typename\typename\main.cpp(10) : warning C4346: 'std::map<int,_Kty>::iterator' : dependent name is not a type
prefix with 'typename' to indicate a type
e:\My Documents\Visual Studio Projects\typename\typename\main.cpp(11) : see reference to class template instantiation 'CTest<T>' being compiled
e:\My Documents\Visual Studio Projects\typename\typename\main.cpp(10) : error C2146: syntax error : missing ';' before identifier 'TEMPLATE_MAP_ITER'
e:\My Documents\Visual Studio Projects\typename\typename\main.cpp(10) : error C2501: 'CTest<T>::TEMPLATE_MAP_ITER' : missing storage-class or type specifiers
Build log was saved at "Documents\Visual Studio Projects\typename\typename\Debug\BuildLog.htm"
typename - 2 error(s), 1 warning(s)
---------------------- Done ----------------------
Build: 0 succeeded, 1 failed, 0 skipped
1>------ 已启动生成: 项目: typename, 配置: Debug Win32 ------
1>正在编译...
1>main.cpp
1>e:\my documents\visual studio 2008\projects\typename\typename\main.cpp(10) : warning C4346: “std::map<int,T>::iterator”: 依赖名称不是类型
1> 用“typename”为前缀来表示类型
1> e:\my documents\visual studio 2008\projects\typename\typename\main.cpp(11): 参见对正在编译的类 模板 实例化“CTest<T>”的引用
1>e:\my documents\visual studio 2008\projects\typename\typename\main.cpp(10) : error C2146: 语法错误 : 缺少“;”(在标识符“TEMPLATE_MAP_ITER”的前面)
1>e:\my documents\visual studio 2008\projects\typename\typename\main.cpp(10) : error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
1>生成日志保存在“file://e:\My Documents\Visual Studio 2008\Projects\typename\typename\Debug\BuildLog.htm”
1>typename - 2 个错误,1 个警告
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
在定义map<int, T>::iterator的时候,由于iterator依赖具体的map,而map中包含了一个模板T,在没有实例化的时候不能确定其类型。
根据编译错误信息,加一个typename前缀即可。
正确的写法:
template <class T>
class CTest
{
public:
typedef map<int, T> TEMPLATE_MAP;
typedef typename map<int, T>::iterator TEMPLATE_MAP_ITER;
};
这里可能会想到为什么TEMPLATE_MAP不需要typename,因为它不依赖其他的名称。
【注】以上代码在VC6.0是可以编译通过的;在VS200*以及g++编译不能通过。
========================================================================================================
原始问题比较隐蔽,在VS200*中编译运行正常,g++上出现了问题:
代码如下:(非问题原始代码)
#include <iostream>
#include <map>
using namespace std;
template <class T>
class CTest
{
public:
/*********************** 1 ***************************/
typedef map<int, T> TEMPLATE_MAP;
//typedef map<int, T>::iterator TEMPLATE_MAP_ITER;
/*****************************************************/
/*********************** 2 ***************************/
struct Node
{
T t;
};
typedef map<int, Node> TEMPLATE_NODE_MAP;
//typedef map<int, Node>::iterator TEMPLATE_NODE_MAP_ITER;
/*****************************************************/
void Add(int key, T value)
{
m_map.insert(make_pair(key, value));
}
void Test()
{
for (map<int, T>::iterator it = m_map.begin(); it != m_map.end(); ++it)
{
cout << it->first << " " << it->second << endl;
}
}
private:
TEMPLATE_MAP m_map;
};
int main()
{
CTest<double> t;
t.Add(1, 3);
t.Add(2, 4);
t.Test();
return 0;
}
这在windows下编译运行良好,在linux下g++编译结果:
main.cpp: In member function 'void CTest<T>::Test()':
main.cpp:30: error: expected `;' before 'it'
main.cpp:30: error: 'it' was not declared in this scope
main.cpp: In member function 'void CTest<T>::Test() [with T = double]':
main.cpp:45: instantiated from here
main.cpp:30: error: dependent-name 'std::map::iterator' is parsed as a non-type, but instantiation yields a type
main.cpp:30: note: say 'typename std::map::iterator' if a type is meant
和windows下的提示信息有一些差距,但是最后一行也给出了解决办法