【问题标题】:Binary operator overloading on a templated class模板类上的二元运算符重载
【发布时间】:2010-11-01 01:07:43
【问题描述】:

我最近试图衡量我的运算符重载/模板能力,作为一个小测试,我在下面创建了 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 转储中列出的(不相关的)左值错误。

【问题讨论】:

    标签: c++ templates operators operator-overloading


    【解决方案1】:

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

    #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;
    }
    

    【讨论】:

      【解决方案2】:
      template <typename T>
      Container<T> operator+ <> (Container<T>& lhs, Container<T>& rhs)
      

      这里应该删除operator+ 之后的“”,因为您只是在声明一个新模板,而不是专门针对通用模板。还有至少g++想在朋友声明之前看到模板声明,所以需要移到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);
            ...
      };
      

      【讨论】:

        【解决方案3】:

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

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

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

        二、行

        Container<int>& c = a + b;
        

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

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

        【讨论】:

        • 我在网上的另一个帖子中发现了这个,这是我个人对两者的偏好(更简洁)。
        • 这将授予对所有模板特化的访问权限(因此 operator+ 可以访问 Container 的私有内容)。询问者的代码只想授予 operator+ 访问权限(只有 operator+ 可以访问 Container 的私有)
        • @litb:我也看到了这个问题,但我在设置这样的场景时遇到了麻烦。您能否提供一个示例代码 sn-p,其中 int 重载访问 float 的私有成员?
        • @GRB,你总是可以人为地构建这样的案例。这是否在您的代码中发生在现实中并不是什么大问题。仅当它发生(偶然)时不会出现错误消息的可能性就足以将其排除。 “const”、“private”和“friend”等概念的想法是记录依赖关系,同时尽可能隐藏和松散。
        • 我知道代码可能不会导致这种情况发生,我遇到的问题是创建这样一个人为的案例。我个人想不出一个,所以我想知道你是否可以。
        【解决方案4】:

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

        template <typename T>
        class Container
        {
        public:
            friend Container operator+ (Container const & lhs, Container const & rhs)
            {
                // ...
            }
        };
        

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

          • 我认为 operator+ 是一个模板函数,不是吗? Container 和 Container 将是两种不同的类型,因此编译器将需要生成两个不同的 operator+ 函数来处理它们。那不是说 operator+ 是一个模板函数吗?
          • 一个函数模板。但是您在模板定义中省略“”是正确的。 (“”只在指定函数模板调用时使用,即使这样也只有在存在同名的非模板函数时才需要。)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-08
          • 2011-04-30
          • 1970-01-01
          • 2018-06-28
          • 1970-01-01
          • 2012-02-07
          • 2021-05-18
          相关资源
          最近更新 更多