5

Right now, I have this code:

bool isAnyTrue() {
    for(std::list< boost::shared_ptr<Foo> >::iterator i = mylist.begin(); i != mylist.end(); ++i) {
        if( (*i)->isTrue() )
            return true;
    }

    return false;
}

I have used Boost here and then but I couldn't really remember any simple way to write it somewhat like I would maybe write it in Python, e.g.:

def isAnyTrue():
    return any(o.isTrue() for o in mylist)

Is there any construct in STL/Boost to write it more or less like this?

Or maybe an equivalent to this Python Code:

def isAnyTrue():
    return any(map(mylist, lambda o: o.isTrue()))

Mostly I am wondering if there is any existing any (and all) equivalent in Boost / STL yet. Or why there is not (because it seems quite useful and I use it quite often in Python).

Albert
  • 65,406
  • 61
  • 242
  • 386

3 Answers3

6

C++ does not (yet) have a foreach construct. You have to write that yourself/

That said, you can use the std::find_if algorithm here:

bool isAnyTrue()
{
    return std::find_if(mylist.begin(), mylist.end(), std::mem_fun(&Foo::isTrue))
           != mylist.end();
}

Also, you should probably be using std::vector or std::deque rather than std::list.

EDIT: sth has just informed me that this won't actually compile because your list contains shared_ptr instead of the actual objects... because of that, you're going to need to write your own functor, or rely on boost:

//#include <boost/ptr_container/indirect_fun.hpp>

bool isAnyTrue()
{
    return std::find_if(mylist.begin(), mylist.end(), 
           boost::make_indirect_fun(std::mem_fun(&Foo::isTrue))) != mylist.end();
}

Note, I haven't tested this second solution.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • Boost has a foreach (`BOOST_FOREACH`). – Albert Aug 08 '10 at 14:35
  • @Albert: Yes, it does. But even in that case, you should prefer algorithm calls to explicit loops. – Billy ONeal Aug 08 '10 at 14:35
  • A queue is not possible because it doesn't allow iteration through its elements. And why vector instead of a list? I need very fast insertion time (should be constant) and don't care about random access at all. – Albert Aug 08 '10 at 14:38
  • 1
    OP is already using boost. `boost::mem_fn` should be more flexible than `std::mem_fun` (or else use `boost::bind`) – UncleBens Aug 08 '10 at 14:42
  • Instead of `make_indirect_fun` or `mem_fun`, Boost.Bind or Boost.Lambda or something a like would probably make it much more clear and easier to read. I think `boost::bind(&Foo::isTrue)` should already work. – Albert Aug 08 '10 at 14:47
  • @Albert: Bind cannot insert a second indirection. You'd still need to use some form of indirect_fun with bind. @UncleBens: The only benefit boost::mem_fn provides is that it automatically selects the correct type -- mem_fun or mem_fun_ref. – Billy ONeal Aug 08 '10 at 15:42
  • In any case it seems that just `boost::mem_fn` compiles and works. From the C++0x description of how `std::mem_fn` should invoke the function, it also seems that these binders are supposed to distinguish between object/reference and anything else, i.e these adaptors shouldn't care if they receive a plain pointer or a smart pointer - dereferencing it looks all the same. – UncleBens Aug 08 '10 at 16:06
  • @UncleBens: That's because `mem_fun` and `mem_fun_ref` work with smart pointers as well. The only difference is that `mem_fun` provides a level of indirection, while `mem_fun_ref` does not. We need two levels of indirection here though... – Billy ONeal Aug 08 '10 at 16:09
  • I'm not entirely sure where the second level of indirection comes from. The calls look quite the same to me: `X* ptr; ((*ptr).*member_fun)();` and `shared_ptr ptr; ((*ptr).*member_fun)();`. Smart pointers exactly mimic the pointer interface. – UncleBens Aug 08 '10 at 16:25
4

Instead of find_if I'd go with a custom any. I like it better in terms of readability over find_if but that's a matter of taste.

template<class ForwardIterator, class Pred>
bool any(ForwardIterator begin, ForwardIterator end, Pred pred) {
  for( ; begin != end; ++begin)
    if(pred(*begin)) return true;

  return false;

  //or
  //return std::find_if(mylist.begin(), mylist.end(), std::mem_fun(&Foo::isTrue))
  //       != mylist.end();

}

bool isAnyTrue() {
  return any(mylist.begin(), mylist.end(), std::mem_fun(&Foo::isTrue));
}

Edit: Alternative any with find_if by Billy ONeal.

pmr
  • 58,701
  • 10
  • 113
  • 156
  • 1
    Nothing wrong with a custom any, but why not implement it in terms of `find_if`? – Billy ONeal Aug 08 '10 at 14:19
  • Ok, well, I wondered mostly why there is no such `any` (or something similar) in Boost yet. This is mostly like I have done it already (not in my question but in my real code), with a custom own `any` function. – Albert Aug 08 '10 at 14:42
  • @Albert - The cool thing about this version of any() is that it uses templates, and works with (no pun intended) any type. It's something you can stuff in your programming toolkit and use anywhere. – J. Polfer Aug 08 '10 at 14:57
4

The new C++ standard has std::any_of, e.g.

bool isAnyTrue()
{
    return std::any_of(mylist.begin(), mylist.end(), std::mem_fn(&Foo::isTrue)); // Note std::mem_fn and not std::mem_fun
}

VS2010 has this implemented.

ronag
  • 49,529
  • 25
  • 126
  • 221