Reputation: 1010
I was reading about std::invoke on cpp reference and was wondering in which situations we would ever need to pass as a first argument a pointer to data member and an object as second argument.
From cpp reference it states this:
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:
...
and then the second point is:
Otherwise, if N == 1 and f is a pointer to data member of class
Ok, let's look at this further and suppose I'm using std::thread
(which constructor's uses std::invoke
):
For example, it is a bit unclear to me when it would be useful (or what can force one) to use a threads this way ?
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;
}
And how a pointer to data member can be associated with a callable concept ?
Upvotes: 1
Views: 153
Reputation: 303347
You might think that only pointers to member functions are useful. That is, something like:
struct Widget {
bool valid() const;
};
std::vector<Widget> widgets;
bool all_valid = std::ranges::all_of(widgets, &Widget::valid);
That would std::invoke
the pointer to member function &Widget::valid
on each of the Widget
s. But you could just as easily have constructed Widget
such that valid
is just a flag instead of being a member function. And checking that all the Widget
s are valid
is just as reasonable a thing to do:
struct Widget {
bool valid;
};
std::vector<Widget> widgets;
bool all_valid = std::ranges::all_of(widgets, &Widget::valid);
The only difference is that this std::invoke
s a pointer to member data instead of a pointer to member function. But still useful.
Upvotes: 3