Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template operator overloading implementation outside class header [duplicate]

The following code defined in 'util.h' compiles and links. However when I move the implementation for the operator overloads into 'util.cc', the linker can not resolve the symbols. Is this this possible to do, or can this not be done due to the nature of templates?

Thanks,


Working

util.h

template<class T>
struct Rect {
  T x, y, w, h;

  friend bool operator ==(const Rect<T> &a, const Rect<T> &b) {
    return (a.x == b.x && a.y == b.y && a.w == b.w && a.h == b.h);
  }

  friend bool operator !=(const Rect<T> &a, const Rect<T> &b) {
    return !(a == b);
  }
};

Not working

util.h

template<class T>
struct Rect {
  T x, y, w, h;

  friend bool operator ==(const Rect<T> &a, const Rect<T> &b);
  friend bool operator !=(const Rect<T> &a, const Rect<T> &b);
};

util.cc

template<class T>
bool operator ==(const Rect<T> &a, const Rect<T> &b)
{
    return (a.x == b.x && a.y == b.y && a.w == b.w && a.h == b.h);
}

template<class T>
bool operator !=(const Rect<T> &a, const Rect<T> &b)
{
    return !(a == b);
}
like image 556
IntelOrca Avatar asked Mar 30 '13 23:03

IntelOrca


People also ask

Can class templates be overloaded?

A template function can be overloaded either by a non-template function or using an ordinary function template.

Can you overload an operator twice C++?

No this is not possible.

Can we overload== operator?

Overloading Binary Operators Suppose that we wish to overload the binary operator == to compare two Point objects. We could do it as a member function or non-member function. To overload as a member function, the declaration is as follows: class Point { public: bool operator==(const Point & rhs) const; // p1.


1 Answers

The answer to your actual question is no for reasons explained in @AndyProwl link, and even if you would have included the operator definitions inside the header util.h the answer would still be no.

The reason is that these operators are actually non-template functions that are injected into the enclosing scope of the class they are defined in as a side-effect of the class template instantiation. In other words, this class template

template<class T>
struct Rect {
  T x, y, w, h;

  friend bool operator ==(const Rect<T> &a, const Rect<T> &b);
  friend bool operator !=(const Rect<T> &a, const Rect<T> &b);
};

generates the following two non-template functions for every type T

bool operator ==(const Rect<T> &a, const Rect<T> &b);
bool operator !=(const Rect<T> &a, const Rect<T> &b);

If you then also define function templates

template<class T>
bool operator ==(const Rect<T> &a, const Rect<T> &b)
{
    return (a.x == b.x && a.y == b.y && a.w == b.w && a.h == b.h);
}

template<class T>
bool operator !=(const Rect<T> &a, const Rect<T> &b)
{
    return !(a == b);
}

and call them in your code, then name lookup and argument deduction proceed without difficulty, but function overload resolution will end in a tie which is broken by the non-template in-class friend functions. But when these are not defined, your program will fail to link.

There are two escapes: define the operators in-class (as you already provided) or (again as alluded to by @AndyProwl) to befriend the general operator templates inside the class with this peculair syntax

// forward declarations
template<typename T> struct Rect;
template<typename T> bool operator==(const Rect<T>&, const Rect<T>&);
template<typename T> bool operator!=(const Rect<T>&, const Rect<T>&);

template<class T>
struct Rect {
  T x, y, w, h;

  // friend of operator templates
  friend bool operator == <>(const Rect<T> &a, const Rect<T> &b);
  friend bool operator != <>(const Rect<T> &a, const Rect<T> &b);
};

// definitions of operator templates follow

Note that befriending templates is a tricky business, as explained in this old column by Herb Sutter.

like image 171
TemplateRex Avatar answered Sep 21 '22 08:09

TemplateRex