2009-02-13 485 views
7

有什麼方法可以組合謂詞嗎?組合謂詞

可以說我有這樣的事情:

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; 
} 

這工作,但現在我想這樣做:

searchResult = find_if(tokens.begin(), tokens.end(), bind2nd(MatchBeginning(), "-b") || not1(bind2nd(MatchBeginning(), "-"))); 

所以我想找到的第一個字符串以「-b」或不以「 - 」開頭的第一個字符串開頭。但是,這給了我一個錯誤(二進制'||'未定義)。

有沒有辦法做到這一點?

回答

5

我可以推薦boost.lambda用於組合此類任務的函數對象。雖然它對於這樣一個簡單的問題有點重量級。 (編輯)查看由xhantt開始的社區wiki答案,這是一個使用STL的好例子。

(老了,過時了,答案),你可以寫你自己的這個工具,類似:

// 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); 
} 

,然後使用它:... lazy_or(bind1st(...), bind1st(...)) ...

+1

您可能還需要一個shim函數來進行編譯:類沒有模板參數推理。 – xtofl 2009-02-13 10:46:53

+0

Thx爲了指出這一點,我編輯了答案,並修復了一些其他部分... – gimpf 2009-02-13 12:22:53

4

如果你想撰寫謂詞,最好到路它可能是使用升壓LAMBDA寫或升壓鳳凰:

// 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 
           ) 
        ); 

爲鳳凰路的可能性之一是利用鳳凰懶功能,以及C液烏爾德類似於下面的一個:

// 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, "-") 
       ); 

然而,爲了完成任務,它可能使更多的採用不同的工具意義上 - 例如:正則表達式(正則表達式升壓或升壓xpressive中)。如果您想處理命令行選項,請使用Boost Program Options。

+0

我希望我能接受這個問題的兩個答案。最後,我發現非圖書館的方式最有趣。不過,感謝您花時間寫出這些片段。 – drby 2009-02-16 08:50:05

5

那麼你有std::logical_orstd::compose2,可以做的工作

find_if(tokens.begin(), tokens.end(), 
    compose2(logical_or<bool>(), 
    bind2nd(MatchBeginning(), "-b"), 
    bind2nd(MatchBeginning(), "-") 
) 
); 

,但我認爲的boost ::拉姆達和/或鳳凰到底更具可讀性,並且是我推薦的解決方案。

積分應該去SGI文件。