将指向数据成员的指针传递给 std::invoke 时有哪些用例和用处?

What are the usecases and usefulness when passing pointer to data member to std::invoke?

我正在阅读有关 std::invoke 的 cpp 参考资料,想知道在哪些情况下我们需要将指向数据成员的指针作为第一个参数传递,将对象作为第二个参数传递。

根据 cpp 参考,它指出:

Invoke the Callable object f with the parameters args. As by INVOKE(std::forward(f), std::forward(args)...).

where INVOKE(f, t1, t2, ..., tN) is defined as follows:

...

然后第二点是:

Otherwise, if N == 1 and f is a pointer to data member of class

好的,让我们进一步看一下,假设我正在使用 std::thread(构造函数使用 std::invoke):

例如,我有点不清楚何时以这种方式使用线程会有用(或者什么可以强制一个)?

struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;

    void print_num(int i) const {
        std::cout << i << '\n';
    }
};

int main() {
    const Foo foo(314159);
    std::thread t(&Foo::num_, foo);
    t.join();
    return 0;
}  

指向数据成员的指针如何与可调用概念相关联?

您可能认为只有指向成员函数的指针才有用。也就是说,类似于:

struct Widget {
    bool valid() const;
};

std::vector<Widget> widgets;
bool all_valid = std::ranges::all_of(widgets, &Widget::valid);

那将 std::invoke 指向每个 Widget 上的成员函数 &Widget::valid 的指针。但是你可以很容易地构造 Widget 这样 valid 只是一个标志而不是一个成员函数。检查所有 Widget 是否都是 valid 也是一件合理的事情:

struct Widget {
    bool valid;
};

std::vector<Widget> widgets;
bool all_valid = std::ranges::all_of(widgets, &Widget::valid);

唯一的区别是这个 std::invoke 是指向成员 data 的指针,而不是指向成员 function 的指针。不过还是有用的。