我在链表类中定义了以下函数.头文件中的声明如下所示:
template <typename T>
class RingBuffer
{
...//stuff
static BLink * NewLink (const T&); // allocator
};
Run Code Online (Sandbox Code Playgroud)
BLink是RingBuffer类中的"链接"类.以下实现代码:
template <typename T>
RingBuffer<T>::BLink * RingBuffer<T>::NewLink( const T& t ) // this is line 114
{
// create a new link in linked list
....
....
}
Run Code Online (Sandbox Code Playgroud)
给我这个编译错误:
./ringbuff.cpp:114:错误:在'令牌之前的预期构造函数,析构函数或类型转换
我很难过为什么它在返回值之前需要一个预期的构造函数,析构函数或类型转换.
这里的问题是你指的是一个嵌套的依赖类型名称(即BLink嵌套在RingBuffer中,它取决于模板参数)
在这种情况下,您需要通过声明这RingBuffer<T>::BLink是一个实际的类型名称来帮助您的编译器.您可以使用typename关键字执行此操作.
template <typename T>
typename RingBuffer<T>::BLink * RingBuffer<T>::NewLink(const T& t)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
RingBuffer<T>::BLink在模板参数T已知之前,编译器无法知道类型名称还是静态成员.当编译器解析您的函数时,模板T是未知的,解决歧义的规则是默认为"这不是类型名称".
另一个简短的例子(公开复制自Scott Meyers的Effective C++):
template<typename C>
void print2nd(const C& container)
{
C::const_iterator * x;
…
}
Run Code Online (Sandbox Code Playgroud)
这可能会更好地说明问题,因为它更紧凑.正如已经说过的那样,解析器不清楚C :: const_iterator是一个类型名称还是一个静态数据成员,因为它不知道什么C时候解析这部分代码(它可能在以后的某个时间点知道)模板实际上是实例化的).因此,为了简化编译器实现者的生活,这种歧义被解析为"不是类型名称",如果程序员想要使用嵌套在依赖于模板参数的任何内容的类型名称,他/她必须使用typename关键字名称的前面让编译器知道它应该被视为类型名称.
不幸的是,在基类列表中使用嵌套依赖类型名称或成员初始化列表中的基类标识符时,该规则有一个例外.
template<typename T>
struct Base {
struct Nested {
Nested(int) {}
};
};
template<typename T>
struct Derived : public Base<T>::Nested { // typename not allowed here
Derived(int i)
: Base<T>::Nested(i) // nor here
{}
};
Run Code Online (Sandbox Code Playgroud)
顺便说一句:您应该在控制台的客户端的字符集设置为UTF-8,让您得到‘*’代替â*â.