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,
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);
}
};
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);
}
A template function can be overloaded either by a non-template function or using an ordinary function template.
No this is not possible.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With