Search code examples
c++templatesoperator-overloadingfriend-class

Overloading an operator through friend function and returning a type different from the rhs parameters


I am attaching the code here and explaining the problem below: Here is the class Bitop:

#ifndef _Bitop_H
#define _Bitop_H

# include <iostream>

double num2fxp(double v, int bits=9, int intbits=5){
  return -0.5;
}

template<int bits = 8, int intbits = 6> 
class Bitop
{
  template<int rhsbits, int rhsintbits> friend class Bitop;

private:
  double value;   // data value

public:
  Bitop(const double& v=0): 
    value(num2fxp(v, bits, intbits))
  {}

  template<int rhsbits, int rhsintbits>
  const Bitop<bits, intbits>& operator = (const Bitop<rhsbits, rhsintbits>& v){
    value = num2fxp(v.value, bits, intbits); 
    return *this;
  }

  template<int rhsbits, int rhsintbits>  
  Bitop<bits, intbits>& operator += (const Bitop<rhsbits, rhsintbits>& v) {
    value = num2fxp(value+v.value, bits, intbits); 
    return *this; 
  }

  template<int lhsbits, int lhsintbits, int rhsbits, int rhsintbits>
  friend Bitop<lhsintbits+rhsintbits+2,  lhsintbits+rhsintbits+1> operator + (const     Bitop<lhsbits, lhsintbits>& x, const Bitop<rhsbits, rhsintbits>& y){ 
    return Bitop<lhsintbits+rhsintbits+2,  lhsintbits+rhsintbits+1>     (num2fxp(x.value+y.value));
  }

  friend std::ostream& operator<< (std::ostream & out, const Bitop& y){return out     <<  y.value ;}

  void Print(){
    std::cout << value<< "<"
      << bits << ","
      << intbits << ">";
  }
};
#endif

And the Test function:

# include <iostream>
# include "Bitop.H"

using namespace std;

int main (int argc, char** argv) {

  Bitop<4,1> a = 0.8;
  Bitop<5,2> b(3.57);
  Bitop<7,3> c;

  c = b;

  cout << "See all attributes of c \n";
  c.Print();cout << "\n";

  c = 7.86;
  cout << "reassign c to a new value\n";
  c.Print();cout << "\n";

  cout << "set b = c \n";
  b = c;
  b.Print();cout<<"\n";

  cout << "set b+=a \n";
  b += a;
  b.Print();cout<<"\n";

  cout << "set b=c+a \n";
  b = c+a;
  b.Print();cout<<"\n";

  return 0;
}

I have a templated class Bitop. I want to overload "+" to add 2 objects with different template parameters and return a third object with parameters different from the rhs and lhs objects, i.e. I want to do the following:

Bitop<5,3> + Bitop<4,2> should return Bitop<10,6>. I declared Bitop to be a friend class of itself so I can access the private members of rhs and lhs objects. But I am getting compilation error (due to redefinition) regardless of whether I call the "+" function.

I am not clear about what I am doing wrong here. Any help is appreciated.

Please note that I left a couple of functions and function calls in the code to ensure that other overloads such as = and += work correctly.


Solution

  • Here's a simplified example that shows the same problem:

    template<int i>
    struct X {
        template<int a, int b>
        friend void foo(X<a>, X<b>) { }
    };
    
    int main()
    {
        X<1> x1;
        X<4> x2; // error: redefinition of foo
    }
    

    Every time a new specialization of X gets instantiated, the definition of foo is inserted in the scope sorounding the template class X. I hope it's clear where the error is coming from.

    Things would be different if the declaration depended on template parameter of the class, like:

    template<int i>
    struct X {
        template<int a, int b>
        friend void foo(X<a+i>, X<b+i>) { } // different definiton
                                            // for each specialization of X
    };
    

    The solution is to define the friend function outside of class:

    template<int i>
    struct X {
        template<int a, int b>
        friend void foo(X<a>, X<b>);
    
    };
    
    template<int a, int b>
    void foo(X<a>, X<b>) { }
    
    int main()
    {
        X<1> x1;
        X<4> x2;
    }