tags:

views:

91

answers:

6

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?

+3  A: 

You have two big problems.

The first issue is that HasTenFoo is a template function. Templates don't actually exist; you can't take the address of one, since it doesn't exist. Instantiations of templates do exist, however. &HasTenFoo is illegal, &HasTenFoo<Bar> is legal. HasTenFoo<Bar> refers to a specific instance of the HasTenFoo template.

The second issue is that the Not class's template parameter has to be the type of the function you're passing it. If you're giving it HasTenFoo<Bar>, the template parameter should be bool(*)(const Bar&).

So, the correct version would be

Not<bool(*)(const Bar&)>(&HasTenFoo<Bar>)

Note that for this to work for both functions and functors, you would have to store a copy of the object/function, not a pointer to them. This is the preferred approach; all standard library functions that take functors keep an internal copy.

dauphic
predicate is a pointer to predicate_t. In my opinion it's unnecessary and it would make things easier if the predicate was stored by value. But it isn't. Shouldn't the template argument be a function instead of a pointer to a function then?
Maciej Hehl
dauphic
Maciej Hehl
Sorry, I overlooked this. Thank you for pointing that out.
dauphic
+3  A: 

There's the built in not1 predicate. It takes a predicate and negates it. This will work with any predicate that derives from unary_predicate. This would remove the need for your hand rolled predicate.

Some combination of that and ptr_fun might achieve what you want.

Edit, Something like this might work (warning, totally untested, not even sure this will compile)

int factorial (int x) {
    ....
}
std::transform (d.begin (), d.end (), v.begin (), std::ptr_fun (factorial));
std::transform (d.begin (), d.end (), v.begin (), not1(std::ptr_fun (factorial)));
Glen
My reading of the documentation suggests that not1 will only work with functors. Does it work with free functions as well?
Bill Carey
@Bill Carey, ptr_fun can be used to convert a free function to a functor. I've never used it, so can't provide any sample code.
Glen
Thanks - I'll give it a try. Haven't dug around in the <functional> header as much as I should!
Bill Carey
@Bill Carey, I've added an edit that shows roughly how this would work for you.
Glen
This usage is correct, and in fact is the reason `ptr_fun` exists. One important note is that for member functions, you need to use `mem_fun_ref` instead.
rlbond
This is a good example too, though you might want to change the second bit to something else, as not1's meant to work with predicates, not transformations, I think?
Bill Carey
A: 

You can use boost::lambda. It allows you to construct predicates and other functors using little code.

Maxim Yegorushkin
A: 

You've done it wrong. The function object idiom accepts function pointers or function objects. In addition, you improperly took the address of a template function. You didn't specify the type. Furthermore, as far as I know, instantiating template operators like operator() requires the explicit .operator() syntax, which most will not use. Also, you generated your function object wrong. Let me show you.

template<typename type_t> class HasEnoughFoo {
public:
  HasEnoughFoo (double bar) { this->bar = bar; }
  bool operator()(const type_t &t) const { return t.foo >= bar; }
private:
  double bar;
};

template<typename predicate_t, typename type_t>
class Not {
public:
  Not(const predicate_t& p) { predicate = p; }

  bool operator()(const type_t &t) const {
    return !(predicate(t));
  }

private:
  predicate_t predicate;
};

Now this functionoid can accept function pointers or function objects that accept the correct arguments.

typedef type_t MyCustomType;
new_list = old_list.subset(Not<HasEnoughFoo<type_t>>(&HasEnoughFoo<type_t>(10.0));
new_list = old_list.subset(Not<decltype(HasTenFoo<&type_t)>>(&HasTenFoo<type_t>));

Essentially:
Put template operators on the function class's type, NOT on the operator or constructors.
Functions MUST have their full template arguments to have their address taken- how else does the compiler know what function's address you want?

Excuse my use of decltype, I couldn't be bothered to type out the function signature. Insert actual signature here.

DeadMG
+3  A: 

Here's an example of your code made to work (I removed the foo member, so it would work with just doubles).

template <typename type_t>
bool HasTenFoo(const type_t &t) {
  return t >= 10.0;
}

class HasEnoughFoo {
public:
  HasEnoughFoo (double bar) { this->bar = bar; }
  template<typename type_t>
  bool operator()(const type_t &t) const { return t >= bar; }
private:
  double bar;
};


template<typename predicate_t>
class Not {
public:
  Not(predicate_t p): predicate(p) { }

  template <typename type_t>
  bool operator()(const type_t &t) const {
    return !predicate(t);
  }

private:
  predicate_t predicate;
};

template <class predicate_type>
Not<predicate_type> Negate(predicate_type p)
{
    return p;
}

#include <iostream>
int main()
{
    std::cout << Negate(HasTenFoo<double>)(11.0) << '\n';
    std::cout << Negate(HasEnoughFoo(13.0))(11.0) << '\n';
}

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.

UncleBens
Perfect - this is exactly what I was looking for. I didn't realize that using an initializer list would remove the requirement for a default constructor (which is what I was passing by pointer instead of by value). The Negate function to hide the template complexity is beautiful as well. Thanks!
Bill Carey
A: 

Functions are functors, which means that if you do everything correctly, your Not template should work as is.

Firstly, there's an obvious error in your Not template declaration - some strange extra template around constructor. This is how it should have looked like

template<typename predicate_t>
class Not {
public:
  Not(predicate_t *p) { predicate = p; }

  template <typename type_t>
  bool operator()(const type_t &t) const {
    return !(*predicate)(t);
  }

private:
  predicate_t *predicate;
};

What that extra template was doing there I don't know. If you were trying to make a template conversion constructor, you were doing it incorrectly. Maybe what you are posting is not the real code.

Now, to use that with your HasTenFoo we'd simply do it as follows

new_list = old_list.subset(Not<bool(const LIST_ELEMENT&)>(&HasTenFoo));

or, to make it a bit more readable

typedef bool OrdinaryFuncPredicate(const LIST_ELEMENT&);
new_list = old_list.subset(Not<OrdinaryFuncPredicate>(&HasTenFoo));

Note the type used as the template argument for Not template. What you were using in your example made no sense (it was a value, not a type, which exactly is what the compiler explicitly told you). Since you are using a function as a predicate, you have to specify the function type as the template argument. This function type should take the list element type as function argument. It is not clear from your original post what the list element type is, so I just used LIST_ELEMENT name as a substitute.

AndreyT