C++ 组合谓词

C++ 组合谓词,c++,stl,functional-programming,predicate,C++,Stl,Functional Programming,Predicate,有什么方法可以组合谓词吗 假设我有这样的东西: class MatchBeginning : public binary_function<CStdString, CStdString, bool> { public: bool operator()(const CStdString &inputOne, const CStdString &inputTwo) const { return inputOne.substr(0, in

有什么方法可以组合谓词吗

假设我有这样的东西:

class MatchBeginning : public binary_function<CStdString, CStdString, bool>
{   public:
          bool operator()(const CStdString &inputOne, const CStdString &inputTwo) const
    {   return inputOne.substr(0, inputTwo.length()).compare(inputTwo) == 0;    }
};

int main(int argc, char* argv[])
{
    CStdString myString("foo -b ar -t az"); 

    vector<CStdString> tokens;

    // splits the string every time it encounters a "-"
    split(myString, tokens, "-", true, true);   

    vector<CStdString>::iterator searchResult = find_if(tokens.begin(), tokens.end(), not1(bind2nd(MatchBeginning(), "-")));        

    return 0;
}
所以我想找到第一个以“-b”开头的字符串,或者第一个不以“-”开头的字符串。但是,这给了我一个错误(二进制'| |'未定义)


有什么方法可以做到这一点吗?

我可以推荐boost.lambda为此类任务组合函数对象。虽然对于这样一个简单的问题来说有点重。(edit)有关使用STL的示例,请参见xhantt启动的社区wiki答案

(旧的,不推荐的,答案)您可以为此编写自己的实用程序,类似于:

// 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);
}
//这里我们定义组合器。。。
模板
类惰性\u或\u impl{
左m_左;
对,对,;
公众:
lazy_或_impl(左常量&左,右常量&右):m_左(左),m_右(右){
typename Left::result_type operator()(typename Left::argument_type const&a)const{
返回m|U左(a)| m|U右(a);
}
};
//以及一个辅助函数,用于推导模板参数
//(thx至xtofl指出这一点)
模板
lazy\u或\u impl lazy\u或(左常量和左常量,右常量和右常量){
返回lazy_或_impl(左、右);
}

然后使用它:
。。。lazy_或(bind1st(…)、bind1st(…)…

如果您想编写谓词,最好的编写方法可能是使用Boost Lambda或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
                               )
                    );
//Lambda方式:
//需要:
//#包括
//#包括
{
使用名称空间boost::lambda;
foo_vec::const_迭代器
=std::查找\u if(
tokens.begin(),
tokens.end(),
绑定(匹配开始(),_1,“-b”)| |!绑定(匹配开始(),_1,“-”)
);
}
//推进绑定方式:
//需要:
//#包括
{
foo_vec::const_迭代器
=std::查找\u if(
tokens.begin(),
tokens.end(),
boost::bind(
std::逻辑_或(),
boost::bind(matchbeging(),_1,“-b”),
!boost::bind(matchbeging(),_1,“-”/!在bind中重载
)
);
对于Phoenix方式,一种可能性是使用Phoenix惰性函数,解决方案可能与下面的类似:

// 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, "-")
                );
//需要:
//#包括
//#包括
//#包括
名称空间phx=boost::phoenix;
结构匹配\u开始\u执行
{
模板
结构结果
{
类型定义布尔类型;
};
模板
布尔运算符()(Arg1 Arg1,Arg2 Arg2)常量
{
//做事
}
};
phx::函数匹配\u开始;
使用phx::arg_name::arg1;
foo_vec::const_迭代器
=std::查找\u if(
tokens.begin(),
tokens.end(),
匹配开头(arg1,“-b”)| |!匹配开头(arg1,“-”)
);
但是,为了完成任务,使用不同的工具可能更有意义,例如:正则表达式(Boost Regex或Boost Xpressive)。如果您想处理命令行选项,请使用Boost程序选项。

您已经有了,而且可以完成这项工作

find_if(tokens.begin(), tokens.end(), 
  compose2(logical_or<bool>(),
    bind2nd(MatchBeginning(), "-b"),
    bind2nd(MatchBeginning(), "-")
  ) 
);
find_if(tokens.begin()、tokens.end(),
组合2(逻辑_或(),
bind2nd(matchstart(),“-b”),
bind2nd(匹配开始(),“-”)
) 
);
但我认为boost::lambda和/或phoenix最终更具可读性,是我推荐的解决方案


学分应该转到SGI文档。

您可能也需要一个shim函数来编译它:类没有模板参数推断。我知道我已经忘记了明显的组合。我只是找到了逻辑或,只是不记得它:-(Cope2的问题是它不是当前C++标准的一部分。嗯,也不是Booost:LAMBDA和凤凰都是标准的一部分。我知道,我的意思是,从哪里可以得到lambda和凤凰,而对于Ceope2,它并不清楚(有些编译器有它,有些没有,等等)。.但我仍然认为boost::lambda最终更具可读性和简洁性,如果我能使用boost,我肯定会使用它。我希望我能接受这个问题的两个答案。最后,我发现非库方式最有趣。不过,感谢你花时间写出这些片段。
find_if(tokens.begin(), tokens.end(), 
  compose2(logical_or<bool>(),
    bind2nd(MatchBeginning(), "-b"),
    bind2nd(MatchBeginning(), "-")
  ) 
);