Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you use std::not1 and std::not2?

Tags:

c++

c++11

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?

like image 336
user4708537 Avatar asked Mar 24 '15 17:03

user4708537


People also ask

What is std :: not1?

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.

Why do we need std :: function?

std::function can hold function objects (including lambdas), as well as function pointers with the correct signature. So it is more versatile.


2 Answers

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.

like image 189
T.C. Avatar answered Oct 16 '22 20:10

T.C.


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)));
                                           ^^^^^^^^
like image 40
ecatmur Avatar answered Oct 16 '22 18:10

ecatmur