Frage

Gibt es eine Möglichkeit, dass Sie Prädikate kombinieren?

Lassen Sie uns sagen, ich habe etwas wie folgt aus:

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

Dies funktioniert, aber jetzt würde Ich mag so etwas wie zu tun:

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

So mag ich die erste Zeichenfolge zu finden, die mit „-b“ beginnt oder die erste Zeichenfolge, die nicht mit nicht gestartet „-“. Aber das gibt mir einen Fehler (binären ‚||‘ undefined).

Gibt es eine Möglichkeit, dies zu tun?

War es hilfreich?

Lösung

Ich kann Boost.Lambda für die Kombination von Funktionsobjekten für solche Aufgaben empfehlen. Obwohl es ein bisschen Schwergewicht für ein solches einfaches Problem. ( Bearbeiten ) Die Community Wiki Antwort Gestartet von xhantt für ein gutes Beispiel unter Verwendung von STL.

(alt, veraltet, Antwort) Sie können Ihr eigenes Programm für dieses schreiben, ähnlich:

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

und dann verwenden: ... lazy_or(bind1st(...), bind1st(...)) ...

Andere Tipps

Nun, Sie haben std :: logical_or und std :: Compose2 , die die Arbeit erledigen kann

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

, aber ich denke, dass boost :: Lambda und / oder Phoenix besser lesbar am Ende ist, und ist meine empfohlene Lösung.

Credits SGI Dokumentation gehen sollte.

Wenn Sie Prädikate komponieren wollen, die schönste Art, es zu schreiben ist wahrscheinlich mit dem Boost-Lambda oder Phoenix Boost:

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

Für die Phoenix Art und Weise eine der Möglichkeiten ist Phoenix faul Funktionen zu nutzen, und die Lösung konnte unten an die wie folgt aussehen:

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

Allerdings Ihre Aufgabe zu erfüllen ist es wahrscheinlich mehr Sinn macht, verschiedene Werkzeuge verwenden - zum Beispiel: reguläre Ausdrücke (Boost Regex oder Erhöhung Xpressive). Wenn Sie die Befehlszeilenoptionen zu handhaben wollen, dann Programmoptionen verwenden steigern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top