6

我最近试图衡量我的运算符重载/模板能力,并作为一个小测试,在下面创建了 Container 类。虽然此代码在 MSVC 2008(显示 11)下编译良好且正常工作,但 MinGW/GCC 和 Comeau 都因operator+过载而窒息。因为我比 MSVC 更信任他们,所以我试图找出我做错了什么。

这是代码:

#include <iostream>

using namespace std;

template <typename T>
class Container
{
      friend Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs);
   public: void setobj(T ob);
     T getobj();
      private: T obj;
};

template <typename T>
void Container<T>::setobj(T ob)
{
   obj = ob;
}

template <typename T>
T Container<T>::getobj()
{
   return obj;
}

template <typename T>
Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs)
{
      Container<T> temp;
      temp.obj = lhs.obj + rhs.obj;
      return temp;
}

int main()
{    
    Container<int> a, b;

 a.setobj(5);
    b.setobj(6);

 Container<int> c = a + b;

 cout << c.getobj() << endl;

    return 0;
}

这是Comeau给出的错误:

Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 27: error: an explicit template argument list is not allowed
          on this declaration
  Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs)
               ^

1 error detected in the compilation of "ComeauTest.c".

我很难让 Comeau/MingGW 打球,所以这就是我求助于你们的地方。我的大脑已经很久没有在 C++ 语法的重压下如此融化了,所以我觉得有点尴尬 ;)。

编辑:消除了初始 Comeau 转储中列出的(不相关的)左值错误。

4

5 回答 5

6

由于此论坛发布,我找到了解决方案。本质上,您需要有一个函数原型,然后才能在类中使用“朋友”,但是您还需要声明该类以正确定义函数原型。因此,解决方案是在顶部有两个原型定义(函数和类)。以下代码在所有三个编译器下编译:

#include <iostream>

using namespace std;

//added lines below
template<typename T> class Container;
template<typename T> Container<T> operator+ (Container<T>& lhs, Container<T>& rhs); 

template <typename T>
class Container
{
      friend Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs);
      public: void setobj(T ob);
              T getobj();
      private: T obj;
};

template <typename T>
void Container<T>::setobj(T ob)
{
      obj = ob;
}

template <typename T>
T Container<T>::getobj()
{
      return obj;
}

template <typename T>
Container<T> operator+ (Container<T>& lhs, Container<T>& rhs)
{
      Container<T> temp;
      temp.obj = lhs.obj + rhs.obj;
      return temp;
}

int main()
{    
    Container<int> a, b;

    a.setobj(5);
    b.setobj(6);

    Container<int> c = a + b;

    cout << c.getobj() << endl;

    return 0;
}
于 2009-06-07T19:44:41.350 回答
2
template <typename T>
Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs)

operator+这里应该删除后面的“<>”,因为您只是在声明一个新模板,而不是专门用于通用模板。也至少g++想在friend声明之前看到模板声明,所以需要在Container. 因此,以下声明顺序有效:

// forward declaration of Container<T>
template <typename T>
class Container;

template <typename T>
Container<T> operator+(Container<T>& lhs, Container<T>& rhs)
{ ... }

template <typename T>
class Container
{
      friend Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs);
      ...
};
于 2009-06-07T19:46:05.213 回答
1

我在 GCC 下试了一下,并通过一些更改让它编译和运行。为了让 GCC 满意,我必须做出两个改变。

一个是friend模板函数的声明。它是它自己的模板声明,与类一分开,所以我在那里使用 U 而不是 Container 类的 T。我也去掉了运算符+之后的<>。除非您正在编写模板专业化,否则我认为您不需要这些。

      template<typename U>
      friend Container<U> operator+ (Container<U>& lhs, Container<U>& rhs);

二、线路

Container<int>& c = a + b;

没有使用 GCC,因为您要求存储对临时的引用(添加的结果)。我删除了与号,以便有一个存储结果的地方。

我刚才看到了您的帖子,由于前向声明,这也有效。我想无论如何我都会将其发布为不需要它们的替代方案。当然我只在 GCC 中测试过......

于 2009-06-07T19:54:45.133 回答
1

你最好直接在类中定义函数。此外,您应该将参数作为const引用传递。

template <typename T>
class Container
{
public:
    friend Container operator+ (Container const & lhs, Container const & rhs)
    {
        // ...
    }
};
于 2009-06-07T20:37:41.880 回答
0

'operator+' 不是成员函数,也不是模板化的。它只是接受模板化参数的 operator+。

 template <typename T>
 Container<T> operator+ (Container<T>& lhs, Container<T>& rhs)
于 2009-06-07T19:47:20.563 回答