【问题标题】:errors porting C++ templates from GCC to Visual C++将 C++ 模板从 GCC 移植到 Visual C++ 时出错
【发布时间】:2011-03-25 07:35:06
【问题描述】:

以下在 GCC 中编译:

cvec.hpp:

template <class T>
class cvec : public deque<T>
{    
   class deque<T>::iterator Find(T);
};

cvec.cpp:

template <class T> 
class deque<T>::iterator cvec<T>::Find(T element)
{

}

在 Visual C++ 中,获取:

error C2242 "typedef name 不能跟随 class/struct/union。

我将头文件中的“类”更改为“类型名”,但收到错误 C3860 - 模板参数列表必须按照模板参数列表中使用的顺序列出参数。在这种情况下只有一个参数,T。除非编译器对 Find(T element) 感到困惑?

【问题讨论】:

  • classtypename 在这种情况下不可互换。 class 在那里不合法。
  • std::deque 派生也是一个糟糕的主意,尤其是如果只是这样你就可以输入deque.Find(x) 而不是使用std::find
  • @jalf:为什么从 std::deque 派生通常是个坏主意?
  • @dvl:这是不安全的,因为标准容器没有虚拟析构函数。如果您不小心,您将在删除时调用未定义的行为。这也是一个坏主意,因为它会使其他用户感到困惑。类的扩展应该通过非成员函数进行,而不是仅仅为了添加成员而派生(使用std::find 而不是添加myhomemadedeque.Find

标签: c++ visual-c++ templates gcc


【解决方案1】:

这在标题中应该是什么意思:

class deque<T>::iterator Find(T);

你没有声明一个类。 typename 关键字在这里是有效的,但 class 没有意义。

.cpp 文件中也是如此:

template <class T> 
typename deque<T>::iterator cvec<T>::Find(T element)

是正确的,class 不是。

除此之外,看起来你正在尝试做的是一个可怕的想法。 std::deque 已经有一个 find 函数。有用。它是正确的。它是有效的。没有必要重新发明它。

标准库容器也不是为派生而设计的。他们没有虚拟析构函数。

所有你得到的结果(除了编译错误)就是你最终会得到一个错误的、效率较低的容器类,这会使其他 C++ 程序员感到困惑,因为它不使用惯用的接口。

【讨论】:

    【解决方案2】:

    这确实应该是一个评论,但我将它作为一个答案,以便我可以格式化它以提高可读性。

    @jalf 和@dvl -- 正如上面的@dvl 所说,没有一个 std 容器具有虚拟析构函数。为什么这很重要?

    假设您从 std::deque 派生了一个类“X”。

    class X : public std::deque<int>
    {
        // whatever ...
    };
    

    现在假设您有一个“X”对象,它由一个基指针指向。

    std::deque<int> *p = new X;
    

    然后你删除它

    delete p;
    

    不会调用派生类 X 的析构函数,这会导致很多问题。

    您的选择:
    1. 不要从标准容器派生。使它们成为数据成员并编写包装器以公开功能。
    2. 仅当派生类没有析构函数且没有具有析构函数的数据成员时,才从标准容器派生。
    3. 如果您从 std 容器派生,切勿通过基指针引用它。

    创建类后,有时很难知道该类将来会如何使用。出于这个原因,许多开发人员严格坚持选项“1”。我个人允许从 std 容器派生,只要它有充分的记录并小心使用。

    【讨论】:

      【解决方案3】:

      这在 2010 年对我有用:

      #include <deque>
      
      template <class T>
      class cvec : public std::deque<T>
      {    
      public:
        typedef typename std::deque<T>::iterator iterator; 
        iterator Find(T element);
      };
      
      template <class T> 
      typename cvec<T>::iterator cvec<T>::Find(T element)
      {
        return std::deque<T>::iterator();
      }
      
      using namespace std;
      
      int main()
      {
        cvec<int> c;
        c.Find(1);
      
        return 0;
      }
      

      【讨论】:

      • 太好了,用 2008 年发布的代码对此进行了测试。没想到对迭代器进行类型定义,而不是使用它具有查找的返回类型。
      猜你喜欢
      • 1970-01-01
      • 2012-08-15
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-08
      相关资源
      最近更新 更多