Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does `std::all_of` not use `std::invoke`?

Tags:

c++

c++17

stl

It has been noted in similar questions (e.g. here) that you cannot pass class method pointers as predicates to std::all_of.

However, with C++17, we have std::invoke, which should make it easy for std::all_of and similar functions to accept member function (and even member variable) pointers.

To be more specific, the following does not compile on GCC 9.2:

#include <algorithm>
#include <vector>

struct S {
    bool check() const { return true; }
};

int main() {
    std::vector<S> vs;
    std::all_of(vs.begin(), vs.end(), &S::check);
}

This Godbolt link contains some example code and a toy version of all_of using invoke.

Why this restriction? Am I missing something? I imagined that when std::invoke was standardised, it should also have been applied to appropriate STL functions.

like image 974
Daniel Steck Avatar asked Oct 14 '19 17:10

Daniel Steck


2 Answers

Reason 1: No one has ever proposed it. P0312R1 proposed to make pointer-to-member-functions callable in the language but was rejected (no consensus for making this change).

Reason 2: With lambda's (and std::bind prior to that), there's very little motivation. If S is a std-defined type (e.g. vector), the member-to-pointer option would be illegal for other reasons.

std::all_of(vs.begin(), vs.end(), [](auto const& s) {return s.check();});
like image 65
Howard Hinnant Avatar answered Oct 24 '22 08:10

Howard Hinnant


The next generation of algorithms (those in the std::ranges namespace) accept predicates that are called with std::invoke, exactly as you suggest (https://godbolt.org/z/uaPoJf):

std::ranges::all_of(vs.begin(), vs.end(), &S::check);

or shorter (https://godbolt.org/z/_qiO8G):

std::ranges::all_of(vs, &S::check);

Furthermore, they accept an additional argument called a “projection”, which is a unary transformation function passed to the algorithm that gets applied to each element before the algorithm operates on the element. For example (https://godbolt.org/z/gWY-OR):

std::ranges::all_of(vs, std::logical_not(), &S::check);

You can already use all of the above with either Casey Carter’s cmcstl2 or Eric Niebler’s range-v3.

like image 28
metalfox Avatar answered Oct 24 '22 08:10

metalfox