I’m working on a problem in C++ that involves lots of subset and transformation operations on a large quantity of data. To that end, I’ve created a map function and something like list comprehensions. I’ve found that a bunch of the predicates I’m writing also have inverses, so I’d need to write:
template <typename type_t>
bool HasTenFoo(const type_t &t) {
return t.foo >= 10.0;
}
and
template <typename type_t>
bool DoesntHaveTenFoo(const type_t &t) {
return t.foo < 10.0;
}
Neither of those is a real example, but they’re representative. I’m also using a fair number of functors like:
class HasEnoughFoo {
public:
HasEnoughFoo (double bar) { this->bar = bar; }
template<typename type_t>
bool operator()(const type_t &t) const { return t.foo >= bar; }
private:
double bar;
};
some of which should have inverses as well. Rather than duplicate code unnecessarily, I’d like to write a functor that takes a predicate as an argument and returns the (value of the) inverse of that predicate. My fist cut at one is below:
/* -- Returns the opposite of some other predicate -------------------------- */
template<typename predicate_t>
class Not {
public:
template <typename predicate_t>
Not(predicate_t *p) { predicate = p; }
template <typename type_t>
bool operator()(const type_t &t) const {
return !(*predicate)(t);
}
private:
predicate_t *predicate;
};
I would call that with something like:
new_list = old_list.subset(Not<HasEnoughFoo>(&HasEnoughFoo(10.0));
or
new_list = old_list.subset(Not<HasTenFoo>(&HasTenFoo));
That seems to work well when predicate_t is a functor like HasEnoughFoo, but fails when predicate_t refers to a regular function like HasTenFoo.
Visual Studio complains that 'HasTenFoo' is not a valid template type argument for parameter 'predicate_t'. Is there any way to write a Not() predicate that will work with functors and functions or am I doomed to write dozens of predicates and their inverses as well?
Here’s an example of your code made to work (I removed the
foomember, so it would work with just doubles).Some important notes:
Not’s constructor uses the initialization list. This removes the requirement that the predicate type has a default constructor (which HasEnoughFoo doesn’t have).
You definitely don’t want to mess with pointers to predicates. Function objects are supposed to be light-weight objects that can be copied without a worry.
Because Not is a template class, with a potentially complicated template argument, but you’d normally just use it as a temporary (as an unnamed argument to a function taking a predicate), add a template function that deduces the complicated type for you (trick used all over the standard library) – here
Negate.