Reputation: 73
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?
Upvotes: 7
Views: 3546
Reputation: 137425
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.
Upvotes: 10
Reputation: 311088
One of approaches is to use std::reference_wrapper
. Here is a demonstrative program
#include <iostream>
#include <functional>
#include <string>
#include <cctype>
#include <algorithm>
int main()
{
std::string s( "...hello" );
auto it = std::find_if( s.begin(), s.end(), std::not1( std::ref( ::ispunct ) ) );
std::cout << *it << std::endl;
return 0;
}
The output is
h
Upvotes: -1
Reputation: 157454
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)));
^^^^^^^^
Upvotes: 4