Is there any way that you can combine predicates?
Lets say I have something like this:
class MatchBeginning : public binary_function
If you want to compose predicates, the nicest way to write it is probably using the Boost Lambda or Boost Phoenix:
// Lambda way:
// Needs:
// #include <boost/lambda/lambda.hpp>
// #include <boost/lambda/bind.hpp>
{
using namespace boost::lambda;
foo_vec::const_iterator it
= std::find_if(
tokens.begin(),
tokens.end(),
bind(MatchBeginning(), _1, "-b") || !bind(MatchBeginning(), _1, "-")
);
}
// Boost bind way:
// Needs:
// #include <boost/bind.hpp>
{
foo_vec::const_iterator it
= std::find_if(
tokens.begin(),
tokens.end(),
boost::bind(
std::logical_or<bool>(),
boost::bind(MatchBeginning(), _1, "-b"),
!boost::bind(MatchBeginning(), _1, "-") // ! overloaded in bind
)
);
For the Phoenix way one of the possibilities is to use phoenix lazy functions, and the solution could look similar to the one below:
// Requires:
// #include <boost/spirit/include/phoenix_core.hpp>
// #include <boost/spirit/include/phoenix_function.hpp>
// #include <boost/spirit/include/phoenix_operator.hpp>
namespace phx = boost::phoenix;
struct match_beginning_impl
{
template <typename Arg1, typename Arg2>
struct result
{
typedef bool type;
};
template <typename Arg1, typename Arg2>
bool operator()(Arg1 arg1, Arg2 arg2) const
{
// Do stuff
}
};
phx::function<match_beginning_impl> match_beginning;
using phx::arg_names::arg1;
foo_vec::const_iterator it
= std::find_if(
tokens.begin(),
tokens.end(),
match_beginning(arg1, "-b") || !match_beginning(arg1, "-")
);
However to accomplish your task it probably makes more sense to employ different tools - for example: regular expressions (Boost Regex or Boost Xpressive). If you want to handle the command line options then use Boost Program Options.
I can recommend boost.lambda for combining function-objects for such tasks. Although it is a bit heavyweight for such a simple problem. (edit) See the community wiki answer started by xhantt for a good example using STL.
(old, deprecated, answer) You can write your own utility for this, similar:
// here we define the combiner...
template<class Left, class Right>
class lazy_or_impl {
Left m_left;
Right m_right;
public:
lazy_or_impl(Left const& left, Right const& right) : m_left(left), m_right(right) {}
typename Left::result_type operator()(typename Left::argument_type const& a) const {
return m_left(a) || m_right(a);
}
};
// and a helper function which deduces the template arguments
// (thx to xtofl to point this out)
template<class Left, class Right>
lazy_or_impl<Left, Right> lazy_or(Left const& left, Right const& right) {
return lazy_or_impl<Left, Right>(left, right);
}
and then use it: ... lazy_or(bind1st(...), bind1st(...)) ...
Well you have std::logical_or and std::compose2 that can do the job
find_if(tokens.begin(), tokens.end(),
compose2(logical_or<bool>(),
bind2nd(MatchBeginning(), "-b"),
bind2nd(MatchBeginning(), "-")
)
);
but I think that boost::lambda and/or phoenix are more readable in the end, and are my recommended solution.
Credits should go to SGI documentation.