Currently if you want to negate a predicate, you have to use a std::<algorithm>_if_not variant or a lambda. But for the sake of academics I want to know if this is possible:
std::string s("hello");
std::find_if(s.begin(), s.end(), std::not1(::ispunct));
Without writing my own function object, how to make this code work?
not1 is a helper function to create a function object that returns the complement of the unary predicate function passed. The function object created is of type std::unary_negate<Predicate>. The unary predicate type must define a member type, argument_type , that is convertible to the predicate's parameter type.
std::function can hold function objects (including lambdas), as well as function pointers with the correct signature. So it is more versatile.
Remember that the correct way to pass chars to the character classification functions (along with toupper and tolower) that came from the C standard library is to convert it first to unsigned char and then to int.
Using std::ref and a reference_wrapper for this is lightweight, and wrong. Using std::function<bool(int)> or std::function<bool(char)> are more heavyweight, and also wrong. In all those cases the char in the string is directly converted to int, which is not the right way to do it.
If you insist on not using a lambda, then
std::find_if(s.begin(), s.end(), std::not1(std::function<bool(unsigned char)>(::ispunct)));
is one right way to do it. Otherwise
std::find_if(s.begin(), s.end(), [](unsigned char c) { return !ispunct(c); });
is easier to understand - and shorter.
The unary predicate type must define a member type,
argument_type, that is convertible to the predicate's parameter type.
The most lightweight way to wrap ::ispunct is to use std::reference_wrapper:
std::find_if(s.begin(), s.end(), std::not1(std::ref(::ispunct)));
^^^^^^^^
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With