Can anyone explain this code? I do not understand the working of not1() and ptr_fun()

Can anyone explain the working of this function?

string rightTrim(const string &str)
{
    string s(str);
    s.erase(find_if(s.rbegin(), s.rend(), not1(ptr_fun<int, int>(isspace))).base(), s.end());
    return s;
}

I don't know the working of not1() and ptr_fun(). Can anyone provide me with a good explanation for this code?

PS: I know, this code removes any white spaces from the end of the string.


Solution 1:

The question is essentially

What is not1(ptr_fun<int, int>(isspace))?

Short answer

You should use std::not_fn(isspace) instead, which clearly states it is a "thing" that expresses the idea that "something is not a space".(¹)(²)

Wordy answer

It is a predicated that asks if its input is not a space: if you apply it to 'a' you get true, if you apply it to ' ', you get false.

However, one the not in the paragraph above explains the reason why the code has not1, but it doesn't say anything about ptr_fun. What is that for? Why couldn't we just write not1(isspace)?

Long story short, not1 is an old generation helper function which was deprecated in C++17 and removed in C++20. It relies on the argument that you pass to it to have a member type named argument_type, but isspace is a free function, not an object of a class providing such a member, so not1(isspace) is ill formed.

ptr_fun came to the rescue, as it can transform isspace in an object which provides the interface that not1 expects.

However, ptr_fun was deprecated even before not1, in C++11, and removed in C++17.

The bottom line is therefore that you should not use either of those: you don't need ptr_fun anymore, and you can use not_fn as a more usable alternative to not1. You can indeed just change not1(ptr_fun<int, int>(isspace)) to std::not_fn(isspace), which also reads much more like "is not a space".


(¹) By the way, stop using namespace std;. It's just the wrong thing to do.

(²) Yes, even if you have to stick to C++14, don't use std::not1. In C++14 you already have generic lambdas, so you can define a quasi-not_fn yourself (working example):

auto not_fn = [](auto const& pred){
    return [&pred](auto const& x){
        return !pred(x);
    };
};