当我在Visual Studio 2005中编译此代码时:
template <class T>
class CFooVector : public std::vector<CFoo<T>>
{
public:
void SetToFirst( typename std::vector<CFoo<T>>::iterator & iter );
};
template <class T>
void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T>>::iterator & iter )
{
iter = begin();
}
我收到这些错误:
c:\home\code\scantest\stltest1\stltest1.cpp(33) : error C2244: 'CFooVector<T>::SetToFirst' : unable to match function definition to an existing declaration
c:\home\code\scantest\stltest1\stltest1.cpp(26) : see declaration of 'CFooVector<T>::SetToFirst'
definition
'void CFooVector<T>::SetToFirst(std::vector<CFoo<T>>::iterator &)'
existing declarations
'void CFooVector<T>::SetToFirst(std::_Vector_iterator<_Ty,_Alloc::rebind<_Ty>::other> &)'
如果我将一个typedef添加到CFooVector模板,我可以获得编译和工作的代码:
template <class T>
class CFooVector : public std::vector<CFoo<T>>
{
public:
typedef typename std::vector<CFoo<T>>::iterator FooVIter;
void SetToFirst( FooVIter & iter );
};
template <class T>
void CFooVector<T>::SetToFirst( FooVIter & iter )
{
iter = begin();
}
我的问题是,为什么使用裸'typename std::vector>::iterator'
声明时typedef不起作用?
答案 0 :(得分:5)
这也编译并揭示了VC ++混淆的来源 - 分配器类型。显然在类VS之外选择不同的默认值。或者它可能无法识别它们是相同的。
在VS2008(按原样)和VS2003(&gt;&gt;之间的空格)上编译
template <class T>
class CFoo
{
public:
T m_t;
};
template <class T>
class CFooVector : public std::vector<CFoo<T>>
{
public:
void SetToFirst(typename std::vector<CFoo<T>, typename CFooVector::_Alloc>::iterator & iter);
};
template <class T>
void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T>, typename CFooVector::_Alloc>::iterator & iter )
{
iter = begin();
}
GCC 3.4想要这个 - &gt; begin()和空间,但是否则它可以在没有显式分配器类型的情况下编译代码......绝对看起来MS编译器不像它应该那么聪明......
答案 1 :(得分:2)
问题不在于typedef,而在于typename。
每当编译器遇到依赖于模板的名称时(基本上,在模板之后使用::
的任何东西),它都无法确定它是类型还是值(它可能是静态int,例如),所以它需要一个提示。
添加typename
时,您指定的是从属成员实际上是一种类型。
在你的typedef示例中,你仍然在typedef声明中有typename,但是一旦声明了typedef,那就不是依赖名。它只是一种类型,因此在引用typedef时不需要typename
。
基本上,编译器无法确定std::vector<CFoo<T>>::iterator
是否为类型。
但它知道FooVIter
是一种类型,因为它是一个typedef。 Typedef总是类型。
答案 2 :(得分:1)
typename是这里最重要的关键字。
重要的是要注意:
>>
它们之间应该有一个空格,以免混淆编译器以为你正在使用
operator>>
没有你的整个代码,我不知道使用typename后出现问题的原因。也许你不需要在类定义之外的定义中?
也可能更好:
template <typename T>
而不是
template <class T>
顺便说一下,除非你非常非常小心,否则从STL课程派生并不是一个好主意。
STL类没有虚拟析构函数。
答案 3 :(得分:0)
似乎对我来说工作得很好如果我做了以下更改 -
template <class T>
class CFoo
{
public:
T m_t;
};
template <class T>
class CFooVector : public std::vector< CFoo<T> >
{
public:
void SetToFirst( typename std::vector<CFoo<T> >::iterator & iter );
};
template <class T>
void CFooVector<T>::SetToFirst( typename std::vector<CFoo<T> >::iterator & iter )
{
iter = begin();
}
我基本上已将std::vector<CFoo<T>>
更改为std::vector<CFoo<T> >
,否则编译器(在我的情况下为gcc)会将其识别为&gt;&gt;操作
答案 4 :(得分:0)
另一个有趣的内容:如果您未在std::
的定义中vector
使用SetToFirst()
名称限定,VS2008会编译您的第二次尝试:
template <class T>
class CFooVector : public std::vector< CFoo<T> >
{
public:
void SetToFirst( typename std::vector< CFoo<T> >::iterator & iter );
};
template <class T>
void CFooVector<T>::SetToFirst( typename /*std::*/vector< CFoo<T> >::iterator & iter )
{
iter = begin();
};
请注意,它似乎只对定义有关,而不是声明。同样有趣的是,如果有“using namespace std;
”或者没有......
我真的不知道该怎么做。