2

I created a template class Number. I overloaded << operator but I'm not able to get % operator working.

template<typename t>
class Number
{
private:
    t n;
public:
    Number(t a) :n{ a } {};
    Number() :n{ t() } {};
    friend ostream & operator<<<>(ostream & os, const Number<t>& a);
    friend Number<t> operator%(Number<t> a, Number<t> b);
};
template<typename t>
ostream & operator<<<>(ostream & os, Number<t> a)
{
    os << a.n;
    return os;
}
template<typename t> 
Number<t> operator%(Number<t> a, Number<t> b)
{
    return Number<t>(a.n % b.n);
}

As you can see <> in << operator definition, that does the job for it. But if I use that in % operator definition, I get a syntax error and if I don't I get "1 unresolved external" error. So my problem can be summed up in two questions- 1. Why do we need to use <> while overloading operator using friend notation? 2. Why its not working for % operator?

Sherry
  • 59
  • 5
  • 1
    Darn good question. I have no good answer, you need someone who groks templates far better than I, but I know the problem goes away if you move the function definition into the class: `friend Number operator%(Number a, Number b) { return Number(a.n % b.n); }` Crap answer, so it's a comment, but it's what I do and move on. – user4581301 May 29 '17 at 04:56
  • There's no need to explicitly write `` inside the class because of [injected class names](https://stackoverflow.com/questions/25549652/why-is-there-an-injected-class-name). – Kinan Al Sarmini May 29 '17 at 04:58

4 Answers4

4

Method 1

Declare the functions before the definition of the class template.

template <typename t> class Number;

template <typename t>
std::ostream & operator<<(std::ostream & os, const Number<t>& a);

template <typename t>
Number<t> operator%(Number<t> a, Number<t> b);

Define the class. Make sure the friend declarations use the template parameter.

template <typename t>
class Number
{
private:
    t n;
public:
    Number(t a) :n{ a } {};
    Number() :n{ t() } {};

    // This makes sure that operator<< <int> is a friend of Number<int>
    // but not of Number<double>
    friend std::ostream & operator<< <t>(std::ostream & os, const Number& a);
    friend Number operator%<t>(Number a, Number b);
};

Implement the functions outside the class definition.

template <typename t>
std::ostream & operator<<(std::ostream & os, const Number<t>& a)
{
    os << a.n;
    return os;
}

template <typename t> 
Number<t> operator%(Number<t> a, Number<t> b)
{
    return Number(a.n % b.n);
}

Working code at http://ideone.com/dx3fC0.

Method 2

Implement the friend functions inside the class template definition.

template <typename t>
class Number
{
   private:
      t n;
   public:
      Number(t a) :n{ a } {};
      Number() :n{ t() } {};
      friend std::ostream& operator<<(std::ostream & os, const Number& a)
      {
         os << a.n;
         return os;
      }

      friend Number operator%(Number a, Number b)
      {
         return Number<t>(a.n % b.n);
      }
};

Working code at http://ideone.com/5PYQnR.


If the friend functions are not overly complex, it is better to use the second method. The overall code structure is simple. If the friend functions are complex, it might make sense to use the first method and implement them outside the class definition.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Thank you. I think I get get what's really going on inside the class now: template specialization of the above declaration. And because the template of `Number` will be specialized after when it's finally put into use, we should be able to pull one more dodge and fully define the templated functions ahead of the definition of `Number`. That will be really freaky because it now looks like we're using parts of `Number` before they've been defined. – user4581301 May 29 '17 at 05:45
  • @user4581301, *That will be really freaky because it now looks like we're using parts of Number before they've been defined.* There is an established pattern called [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) that does exactly that. – R Sahu May 29 '17 at 05:53
  • 1
    better yet, implement binary operators in terms of unary operators and/or methods. then you don't need them to be friends. – Richard Hodges May 29 '17 at 05:58
1

You should first declare the operator as a function template before "befriending" it in the class. See this and this for more details on how to properly do that.

The reason you got away with operator << I suspect, is a using namespace std not shown in your question, which brings in the templated operator << declaration from <iostream>.

This should work:

#include <iostream>

template<typename T>
class Number;

// Declare the operators here.
template<typename T>
std::ostream & operator<<(std::ostream & os, const Number<T>& a);

template<typename T>
Number<T> operator%(Number<T> a, Number<T> b);

template<typename T>
class Number
{
private:
    T n;
public:
    Number(T a) :n{ a } {};
    Number() :n{ T() } {};

    friend std::ostream & operator<< <T>(std::ostream & os, const Number& a);

    friend Number operator% <T>(Number a, Number b);
};

template<typename T>
std::ostream & operator<<(std::ostream & os, const Number<T>& a /* was Number<T> ==> signature mismatch */) 
{
    os << a.n;
    return os;
}

template<typename T> 
Number<T> operator%(Number<T> a, Number<T> b)
{
    return Number<T>(a.n % b.n);
}

int main() {
    Number<int> a(5);
    Number<int> b(6);
    auto c = a % b;
    std::cout << a << std::endl;
    return 0;
}
Kinan Al Sarmini
  • 533
  • 3
  • 19
0

Define these functions in the class body and save yourself the hassle. Also, in case that the left-hand side operand of % is Number you don't have to make it a friend.

#include <iostream>

using std::ostream;

template<typename t>
class Number
{
private:
    t n;
public:
    Number(t a) :n{ a } {};
    Number() :n{ t() } {};

    Number operator%(Number rhs)
    {
        return Number(n % rhs.n);
    }

    friend ostream & operator<<(ostream & os, Number a)
    {
       os << a.n;
       return os;
    }
};


int main()
{
  Number<int> n1(4);
  Number<int> n2(2);

  std::cout << n1 << ' ' << n2 << '\n';

  Number<int> n3 = n1 % n2;
  std::cout << n3 << '\n';
}
Henri Menke
  • 10,705
  • 1
  • 24
  • 42
0

You could make the friend operator a templated operator itself:

template<typename t>
class Number
{
private:
    t n;
public:
    Number(t a) :n ( a ){};
    Number() :n( t() ) {};

    template<typename TT>
    friend Number<TT> operator%(Number<TT> a,const Number<TT>& b);
};

template<typename t> 
Number<t> operator%(Number<t> a,const Number<t> &b)
{
    return Number<t>(a.n % b.n);
}


int _tmain(int argc, _TCHAR* argv[])
{
    Number<int> a;
    Number<int> b;

    Number<int> c = a %b;
    return 0;
}

See explanation about extrovert declaration here.

Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185