Combining Predicates

后端 未结 3 1527
夕颜
夕颜 2021-01-05 09:08

Is there any way that you can combine predicates?

Lets say I have something like this:

class MatchBeginning : public binary_function

        
相关标签:
3条回答
  • 2021-01-05 09:26

    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.

    0 讨论(0)
  • 2021-01-05 09:47

    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(...)) ...

    0 讨论(0)
  • 2021-01-05 09:51

    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.

    0 讨论(0)
提交回复
热议问题