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

StackOverflow https://stackoverflow.com/questions/18382818

Pergunta

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.

Foi útil?

Solução

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

Outras dicas

You don't really need to define operator+ as friend:

template<int I>
class A
{
  double X;
  template<int> friend class A;
public:
  A(A const&) = default;

  A(double x)
    : X(x) {}

  template<int J>
  A(A<J> const&a)
    : X(a.X) {}

  template<int J>
  A<I+J> operator+ (A<J> const&a)
  { return A<I+J>(X+a.X); }
};

int main()
{
  A<0> a0(3);
  A<1> a1(4);
  auto ax = a0+a1;
}

Moreover, the result returned by operator+(a,b) should really be identical to that obtained by operator=(a) followed by operator+=(b).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top