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 char
s 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