我有以下代码,无法编译
template < typename T >
class Base
{
public:
typedef T * TPtr;
void func()
{
}
};
template < typename T >
class Derived : public Base< T >
{
public:
using Base< T >::TPtr;
using Base< T >::func;
TPtr ptr;
};
int main( int c, char *v[] )
{
Derived< int > d;
d.func();
}
编译器发出以下内容。
t.cpp:16: error: 'TPtr' does not name a type
t.cpp:16: note: (perhaps 'typename Base<T>::TPtr' was intended)
现在我知道我可以简单地按照编译器的建议去做但我无法理解为什么
using Base< T >::TPtr;
不起作用。
如果我注释掉“TPtr ptr
”行,那么它会编译,证明“using Base< T >::func;
”语句有效。
有什么想法吗?
答案 0 :(得分:9)
Base< T >::TPtr
是一个所谓的依赖名称,因此您需要在其前面添加typename
以使声明有效。
此外,using
不适用于typename
,因此您需要使用typedef
代替:
typedef typename Base<T>::TPtr TPtr;
问题是编译器无法决定 - 不知道T
是什么! - 此上下文中的TPtr
是否指定类型或变量/函数。为了避免含糊不清,除非另有明确说明,否则它总是假设后者(因此需要typename
)。
答案 1 :(得分:2)
这是缺陷的一部分。虽然C ++ 03 提供了using typename
,但不提供了必要的规则来说明using声明声明的名称是类型名称。它只是提供了一个工具,说使用声明中引用的名称是一个类型名称。所以你可以实际做以下事情,但在编译器中取得了不同的成功。有些人会让它发挥作用,但有些人不会。
template < typename T >
class Derived : public Base< T >
{
public:
using typename Base< T >::TPtr;
using Base< T >::func;
// up to here it's alright
TPtr ptr;
// but this may only work on some compilers
};
This issue已针对C ++ 0x修复。对于C ++ 03,解决它的方法是使用typedef
代替。
答案 2 :(得分:1)
我无法理解为什么:
使用Base&lt; T> :: TPtr;
不起作用。
由于可能的模板特化,Base< T >::TPtr
可以是任何东西:类型名称,变量名称,函数等。
使用关键字typename
,您告诉编译器它只能是类型名称。
Here is a decent explanation它解决了什么样的含糊之处。向下滚动到“问题”,它会精确地覆盖您的案例。
答案 3 :(得分:0)
当你写作 TPtr ptr;
它被视为Base<T>::TPtr
,编译器将假设这是Base<T>
的成员变量或Base<T>
的方法(这是它将要执行的操作,因为{{1} }是一个'依赖名称',不幸的是在这种情况下,编译器将假定变量或函数而不是类型),从而使声明无效。
关键字Base<T>::TPtr
允许编译器明确知道typename
为类型命名。