traduccion tecnicas proceso compilacion como cognitivo c++ stl functional-programming predicate

c++ - proceso - tecnicas de compilacion



Combinando Predicados (3)

¿Hay alguna forma de combinar predicados?

Digamos que tengo algo como esto:

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

Esto funciona, pero ahora me gustaría hacer algo como:

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

Así que me gustaría encontrar la primera cadena que comienza con "-b" o la primera cadena que no comienza con "-". Sin embargo, esto me da un error (binario ''||'' undefined).

¿Hay alguna manera de hacer esto?


Bueno, tienes std :: logical_or y std :: compose2 que pueden hacer el trabajo

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

pero creo que boost :: lambda y / o phoenix son más legibles al final, y son mi solución recomendada.

Los créditos deben ir a la documentación de SGI.


Puedo recomendar boost.lambda para combinar objetos funcionales para tales tareas. Aunque es un poco pesado para un problema tan simple. ( edit ) Vea la respuesta wiki de la comunidad iniciada por xhantt para un buen ejemplo usando STL.

(viejo, obsoleto, respuesta) Puede escribir su propia utilidad para esto, 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); }

y luego ... lazy_or(bind1st(...), bind1st(...)) ... : ... lazy_or(bind1st(...), bind1st(...)) ...


Si desea redactar predicados, la mejor forma de escribirlo probablemente sea utilizando Boost Lambda o 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 ) );

Para Phoenix, una de las posibilidades es utilizar las funciones perezosas de Phoenix, y la solución podría ser similar a la siguiente:

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

Sin embargo, para realizar su tarea, probablemente tenga más sentido emplear diferentes herramientas, por ejemplo: expresiones regulares (Boost Regex o Boost Xpressive). Si desea manejar las opciones de la línea de comando, entonces use las Opciones del Programa Boost.