2

Context: C++03 only + the use of boost is authorized

I'd like to raise the same question as in

How to negate a predicate function using operator ! in C++?

... but with an overloaded boolean predicate, that is:

struct MyPredicate
{
    bool operator()(T1) const;
    bool operator()(T2) const;
};

Clearly, MyPredicate cannot be derived from std::unary_function as it is impossible to define a single argument_type.

The aim is to use MyPredicate as argument to range adaptors, with a readable syntax like this:

using boost::for_each;
using boost::adaptors::filtered;

list<T1> list1;
list<T2> list2;

for_each(list1 | filtered(!MyPredicate()), doThis);
for_each(list2 | filtered(!MyPredicate()), doThat);

Of course, any solution involving explicit disambiguation is of no interest here.

Thank you in advance.

[ACCEPTED SOLUTION]

I'm using a slightly modified version of Angew's solution:

template <class Predicate>
struct Not
{
  Predicate pred;

  Not(Predicate pred) : pred(pred) {}

  template <class tArg>
  bool operator() (const tArg &arg) const
  { return !pred(arg); }
};

template <class Pred>
inline Not<Pred> operator! (const Pred &pred)
{
  return Not<Pred>(pred);
}

template <class Pred>
Pred operator! (const Not<Pred> &pred)
{
  return pred.pred;
}

Note that operators && and || can benefit from this trick likewise.

Community
  • 1
  • 1
koral
  • 442
  • 3
  • 11
  • can you use multiple inheritance? `struct MyPredicate : unary_function, unary_function` – pippin1289 Oct 18 '13 at 15:53
  • 3
    I didn't try, but given that both `unary_function` derivations will define the `argument_type`, I have no reason to think this won't end into a definition conflict. – koral Oct 18 '13 at 16:06

2 Answers2

1

You can do this:

struct MyPredicate
{
  bool positive;
  MyPredicate() : positive(true) {}

  bool operator() (T1) const {
    return original_return_value == positive;
  }
  bool operator() (T2) const {
    return original_return_value == positive;
  }
};

inline MyPredicate operator! (MyPredicate p) {
  p.positive = !p.positive;
  return p;
}

To address your concern of forgetting to use positive, you could try an alternative approach with a wrapper class.

template <class Predicate>
struct NegatablePredicate
{
  Predicate pred;
  bool positive;

  NegatablePredicate(Predicate pred, bool positive) : pred(pred), positive(positive) {}

  template <class tArg>
  bool operator() (const tArg &arg) const
  { return pred(arg) == positive; }
};

template <class Pred>
inline NegatablePredicate<Pred> operator! (const Pred &pred)
{
  return NegatablePredicate<Pred>(pred, false);
}

You can also add an overload for optimisation purposes:

template <class Pred>
inline NegatablePredicate<Pred> operator! (const NegatablePredicate<Pred> &pred)
{
  return NegatablePredicate<Pred>(pred.pred, !pred.positive);
}

To address possible concern with the wide scope of the template operator!, you can employ boost::enable_if magic.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • This should work, but is unsatisfying to me because it is not foolproof: one has to think about comparing to `positive`, otherwise the `operator!` won't work as expected, and this cannot be detected at compile time. – koral Oct 18 '13 at 16:28
  • Sidenote: to avoid defining `operator!` for each predicate, one would encapsulate the boolean into a base class `BooleanPredicate` on which one could define `operator!` once and for all. – koral Oct 18 '13 at 16:34
  • @koral I've added an alternative which should be foolproof. – Angew is no longer proud of SO Oct 18 '13 at 16:43
  • This is working, thank you. I still have the feeling we are reimplementing what is already done in [boost::lambda](http://www.boost.org/doc/libs/1_54_0/doc/html/lambda.html) or [boost::phoenix](http://www.boost.org/doc/libs/1_54_0/libs/phoenix/doc/html/index.html), though I can't figure out how to use those libraries to get the same result. – koral Oct 29 '13 at 10:34
0

You actually can derive from std::unary_function:

template<typename T>
struct MyPredicate : std::unary_function<T, bool>
{
    bool operator()(T) const;
};
Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • 5
    Unless I'm mistaken, this requires explicit disambiguation (`filtered(!MyPredicate())`), right ? – koral Oct 18 '13 at 16:03
  • @Koral: That is correct. I missed the statement at the bottom of the question wanting to avoid it ... – Zac Howland Oct 18 '13 at 16:13