为什么`std :: all_of`不使用`std :: invoke`?

Dan*_*elS 3 c++ stl c++17

在类似的问题(例如,此处)中已经指出,您不能将类方法指针作为谓词传递std::all_of

但是,对于C ++ 17,我们有std::invoke,这应该使std::all_of相似的函数更容易接受成员函数(甚至成员变量)指针。

更具体地说,以下内容无法在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);
}
Run Code Online (Sandbox Code Playgroud)

Godbolt链接包含一些示例代码和all_of使用invoke 的玩具版本。

为什么有这个限制?我想念什么吗?我以为当std::invoke标准化时,它也应该应用于适当的STL函数。

How*_*ant 5

原因1: 没有人提出过它。 P0312R1建议使该成员函数的指针可在该语言中调用,但被拒绝(对此更改未达成共识)。

原因2:使用lambda(std::bind在此之前),动力不足。如果S是std定义的类型(例如vector),则出于其他原因,成员到指针选项将是非法的。

std::all_of(vs.begin(), vs.end(), [](auto const& s) {return s.check();});
Run Code Online (Sandbox Code Playgroud)

  • 我认为`std :: mem_fn`是一个更有说服力的原因(就可读性而言)比`bind`更有意义。 (3认同)
  • 原因3:不应该使用invoke,我们应该使指向成员的指针成为可调用的(我觉得有责任在相关的地方发表此评论)。 (2认同)

met*_*fox 5

下一代算法(std::ranges命名空间中的算法)接受用 调用的谓词std::invoke,完全按照您的建议(https://godbolt.org/z/uaPoJf):

std::ranges::all_of(vs.begin(), vs.end(), &S::check);
Run Code Online (Sandbox Code Playgroud)

或更短(https://godbolt.org/z/_qiO8G):

std::ranges::all_of(vs, &S::check);
Run Code Online (Sandbox Code Playgroud)

此外,它们接受一个称为“投影”的附加参数,这是一个传递给算法的一元变换函数,该函数在算法对元素进行操作之前应用于每个元素。例如(https://godbolt.org/z/gWY-OR):

std::ranges::all_of(vs, std::logical_not(), &S::check);
Run Code Online (Sandbox Code Playgroud)

您已经可以将上述所有内容与 Casey Carter 的cmcstl2或 Eric Niebler 的range-v3 一起使用