Reputation: 53881
Id like to say that there's a ton of C++ Overloading questions already on SO, but after an hour of looking at them and other posts on forums and newsgroups, I'm still stumped.
Background
I've created a namespace, call it A, where a bunch of classes have the same way of implementing the < operator. In order to avoid code duplication, I wrote this:
namespace A{
template<typename T>
bool operator< (const T&, const T&);
}
In a header file called operator_forwards.h along with a few other declarations. I then made it a friend to the correct classes by adding a line like this:
//example.h
#include "operator_forwards.h"
namespace A{
template<typename T>
class Example{
public:
friend bool operator< <>(const Example<T>&, const Example T&);
private:
T start;
};
}
Finally, I put the definition in a file called operators.h like this:
namespace A{
template<typename T>
bool operator<(const T& lhs, const T& rhs){
using std::operator<;
return lhs.start<rhs.start;
}
}
And included everything in one header file:
//A.h
#include "example.h"
#include "operators.h"
The Problem
The problem is when I call operator< like this:
Example<vector<int>::iterator> ex1(**foo**);
Example<vector<int>::iterator> ex2(**bar**);
ex1<ex2;
It calls A::operator< fine, however it recursively calls itself to do ex1.start<ex2.start
rather then looking up the more specialized operator< for vector::iterator. Resulting in the error C2039: start is not a member of vector::iterator.
Does anyone have any advice for making sure that A::operator< calls the correct operator< for ex1.start?
Note: there are about 20 classes that use A::operator< so if I could avoid defining it in each class separately that'd be awesome.
Upvotes: 0
Views: 83
Reputation: 36497
My humble suggestion: don't do that.
You'll have to deal with this problem in more places than the implementation of A::operator<
. Any code anywhere in A
can potentially get bamboozled by this unexpected template which claims to support operator<
for anything, but can only actually perform it on types which have a start
member.
In your case, you're putting a friend
declaration in every relevant class anywhere. It's barely any more code to simply implement it in those classes. If that offends your code-duplication sensibilities, then consider a shared base class:
template <typename T>
class IterWrapper {
public:
IterWrapper() {}
explicit IterWrapper(T it) : start(it) {}
bool operator< (const IterWrapper<T>& rhs) { return start < rhs.start; }
protected:
T start;
};
Upvotes: 2