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.