Templates and operator overloading obfuscate the real problem here. Look at this small piece of code which yields the same error:
void f(int &);
int main()
{
int *ptr;
f(ptr);
}
The compiler won't let you pass a pointer where a reference is expected. This is what you try to do with your derived class. As you operate on a concrete Always
, the base versions of operator()
are not considered.
Look how the situation changes when you operate instead on a pointer (or reference) to the base class:
int main(){
Predicate<int> *ptr = new Always<int>;
int i = 1000;
(*ptr)(&i);
delete ptr;
}
This compiles fine because the base-class operators are now considered for overload resolution. But this is just to make you understand the problem better. The solution is to apply the Non-Virtual Interface Idiom. Make your operators non-virtual and implement them in terms of private virtual functions:
template<typename Type>
class Predicate{
public:
Predicate() {};
virtual ~Predicate(){};
bool operator()(const Type & value) { return operatorImpl(value); }
bool operator()(const Type * value) { return operatorImpl(value); }
private:
virtual bool operatorImpl(const Type & value) = 0;
virtual bool operatorImpl(const Type * value) {
return (*this)(*value);
}
};
template<typename Type>
class Always : public Predicate<Type>{
public:
~Always(){};
private:
bool operatorImpl(const Type & value){return true;}
};