代码之家  ›  专栏  ›  技术社区  ›  David Coufal

为什么需要在此模板中使用typedef?

  •  3
  • David Coufal  · 技术社区  · 17 年前

    在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添加到cfovector模板中,我可以获取要编译和工作的代码:

      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();
      }
    

    我的问题是,为什么typedef在使用bare时工作 'typename std::vector>::iterator' 声明无效?

    5 回复  |  直到 17 年前
        1
  •  5
  •   Eugene    17 年前

    这也编译并揭示了VC++混淆的根源——分配器类型。显然,在类外,vs选择不同的默认值。或者它可能无法识别它们是相同的。

    在VS2008(按原样)和VS2003(空间介于>>)上编译

    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想要这个->begin()和空格,但是它可以编译代码而不需要显式的分配器类型…看起来微软编译器并没有它应有的聪明…

        2
  •  2
  •   Stack Overflow is garbage    17 年前

    问题不在于typedef,而在于typename。

    每当编译器遇到依赖于模板的名称时(基本上,任何使用 :: 在模板之后,它无法确定它是类型还是值(例如,它可以是静态int),因此需要一个提示。

    当你添加 typename 您指定的依赖成员实际上是一个类型。

    在typedef示例中,typedef声明中仍有typename,但一旦声明typedef,它就不是依赖名称。这只是一种类型,所以 类别名 引用typedef时不需要。

    基本上,编译器不能确定 std::vector<CFoo<T>>::iterator 是一种类型。

    但它知道 FooVIter 是类型,因为它是typedef。typedef总是类型。

        3
  •  1
  •   Juan    17 年前

    typename是这里最重要的关键字。

    重要的是要注意:

    >>
    

    它们之间应该有一个空格,以免混淆编译器,使其认为您正在使用

    operator>>
    

    如果没有完整的代码,我不知道为什么在使用typename之后会有问题。也许在类定义之外的定义中不需要它?

    此外,最好是:

    template <typename T>
    

    而不是

    template <class T>
    

    顺便说一句,从STL类派生不是一个好主意,除非您非常非常小心。

    STL类没有虚拟析构函数。

        4
  •  0
  •   Vishesh Handa    17 年前

    对我来说好像很好 如果 我做了以下更改-

    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)会将其识别为>>运算符。

        5
  •  0
  •   Michael Burr    17 年前

    另一个有趣的地方:如果不使用 std:: 姓名资格 vector 在定义中 SetToFirst() :

      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; “或不…

    我真的不知道该怎么办。