为什么在此模板中使用typedef是必要的?

时间:2009-07-31 21:50:36

标签: c++ templates typedef typename

当我在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不起作用?

5 个答案:

答案 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;”或者没有......

我真的不知道该怎么做。