6

I've a code:

class cabc{
public:
    void pr()
    {
        cout<<"abcdef";
    }
};
int main()
{

    cabc cap;
    auto f = async(cap.pr);
    f.get();
    return 0;
}

This code is not working. I know the same thing can be done using:

auto f = async(&cabc::pr,cap);

This is working. But why the first approach is not working?

  • 2
    Why *would* you expect the first approach to work? – juanchopanza Dec 03 '13 at 08:55
  • 1
    It's not just `async`, it's just how the language works (or not work). – Mark Garcia Dec 03 '13 at 08:55
  • cap.pr is function like the regular one. Then why it should not work? @juanchopanza –  Dec 03 '13 at 08:56
  • 5
    No, `cap.pr` is not a function. `cap.pr(arg)` means something like "call `cabc::pr` on `cap` with argument `arg`". `cap.pr` by itself doesn't make sense. – juanchopanza Dec 03 '13 at 08:57
  • 2
    It's arguable that C++ *should* have a concept of a "bound member function pointer" in the core language, as many people do intuitively expect that the syntax you want to use should work. However, it does not, and adding the feature to the existing type system would not be trivial. On the other hand, it is easy to emulate it on the library level -- it's called `std::mem_fn` and it is internally used by `std::async` to make the `async(&a::b, c)` syntax work. – JohannesD Dec 03 '13 at 09:51

2 Answers2

12

cap.pr is an incomplete member function call expression. You must follow it with parentheses containing the appropriate function arguments to make a valid C++ expression.

You can't therefore pass cap.pr to std::async or any other function.

To pass a member function to std::async you need to use the syntax you found:

auto f=std::async(&capc::pr,cap);

Though in this case, you need to be aware that the cap object is copied. You could also use

auto f=std::async(&capc::pr,&cap);

to just pass a pointer to cap.

If the pointer-to-member-function syntax is unwelcome then you can use a lambda:

auto f=std::async([&]{cap.pr();});

This isn't quite the same: it doesn't pass the member function pointer and object pointer to std::async, it passes a lambda object containing a reference to cap that calls its pr member function directly. However, the result is essentially the same.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155
1

Have a look at the function signature for async:

template< class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type>
    async( Function&& f, Args&&... args );

(from cppreference)

It should be apparent that, firstly, whatever Function&& is, it can't be the case that cap.pr and &cabc::pr are both of that type.

More precisely, though, Function&& is supposed to be an rvalue-reference to a function pointer. &cabc::pr is just the syntax for a pointer-to-member-function, and because it's a member function, a pointer to the object itself needs to be the first argument. If cap.pr were a C-style function pointer, then your first sample might work.

Honestly, I'm not sure why your second sample works since you're not passing in a pointer to your object.

There are a number of other answers to similar questions. For example: How to, in C++11, use std::async on a member function?

Community
  • 1
  • 1
Ben Collins
  • 20,538
  • 18
  • 127
  • 187