Boost logo

Boost Users :

From: Michael Fawcett (michael.fawcett_at_[hidden])
Date: 2008-02-15 11:24:26


On Fri, Feb 15, 2008 at 10:19 AM, dizzy <dizzy_at_[hidden]> wrote:
>
> On Friday 15 February 2008 17:07:21 Michael Fawcett wrote:
> > On Fri, Feb 15, 2008 at 3:14 AM, Jean-Pierre Bergamin <james_at_[hidden]>
> wrote:
> > > Could there be a way to provide a function object safe_logical_and that
> > > only evaluates the second argument if the first one is true?
> >
> > I've written something like that before as:

<snip code with typos>

> > but if you needed function arguments that weren't available to be
> > bound at and_ construction time you'd have to do some more trickery.
> > This would also scale well using variadic templates.
>
> I don't understand how this code does not evaluate the second argument if the
> first one isn't true (the previous poster explicitely requested that). When
> you construct the above functor evaluation of the expression given for "f1"
> argument will happen which may run into UB, ie the classical "if (p &&
> p->flag)" idiom is broken (and you seem to recognize that... no idea then
> what you ment with the code).

I might be showing my misunderstanding of all the intricacies at work here...

Maybe I am not understanding his intents, or maybe we are talking to
two different points? I have pasted below his original code, modified
to use something like what I posted (and also to have a result when &&
is used).

Are you saying that short-circuit evaluation doesn't happen here, i.e.
the second(t) call happens no matter what?

I thought it was understood that overloading && would have that
effect, and the OP understood that too, which is why he suggested a
safe_logical_and. That means overloading && is out of the question,
which we all seem to agree on, but I am feeling a little silly trying
to figure out why the below code is rubbish.

#include "boost/bind.hpp"

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using namespace boost;

struct employee {
       employee(int id, const string &name) :
               id(id), name(name) {}

       int id;
       string name;
};

ostream &operator<<(ostream &o, const employee &e) {
       o << e.id << " - " << e.name << endl;
       return o;
}

template <typename F0, typename F1>
struct and_ {
  F0 first;
  F1 second;

  and_(F0 f0, F1 f1) : first(f0), second(f1) { }

  template <typename T>
  bool operator()(const T &t) const {
     return first(t) && second(t);
  }
};

template <typename F0, typename F1>
struct or_ {
  F0 first;
  F1 second;

  or_(F0 f0, F1 f1) : first(f0), second(f1) { }

  template <typename T>
  bool operator()(const T &t) const {
     return first(t) || second(t);
  }
};

template <typename F0, typename F1>
and_<F0, F1> safe_logical_and(F0 f0, F1 f1) {
        return and_<F0, F1>(f0, f1);
}

template <typename F0, typename F1>
or_<F0, F1> safe_logical_or(F0 f0, F1 f1) {
        return or_<F0, F1>(f0, f1);
}

int main() {
        typedef vector<employee> emp_container;
        emp_container staff;
        staff.reserve(4);

        staff.push_back(employee(1, "John"));
        staff.push_back(employee(2, "Paula"));
        staff.push_back(employee(3, "Sara"));
        staff.push_back(employee(4, "Geroge"));

        emp_container::const_iterator e = find_if(staff.begin(), staff.end(),
                safe_logical_and(safe_logical_or(bind(&employee::name, _1) ==
"Paula", bind(&employee::name, _1) == "John"),
                bind(&employee::id, _1) <= 4));

        if (e != staff.end()) {
                cout << "Found: " << *e << endl;
        }
}

--Michael Fawcett


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net