3

I am trying to evaluate a part of my code asynchronously

#include <stdio.h>
#include <string>
#include <memory>
#include <future>
#include <map>

namespace IG
{
    typedef std::map<uint, std::string> CadDef;

    class FooFoo
    {
        CadDef foo()
        {
            CadDef cdef{};
            cdef[1] = "aa";
            return cdef;
        }
    };
}

int main()
{
    auto ptr = std::make_unique<IG::FooFoo>();
    std::future<IG::CadDef> resFut = std::async(ptr->foo);
    auto res = resFut.get();
    return 0;
}

But the code doesn't compile - (On gcc)

error: invalid use of non-static member function ‘IG::CadDef IG::FooFoo::foo()’

(on msvc -- my main program, from where I abstracted the minimal example)

error C3867: 'IG::FooFoo::foo': non-standard syntax; use '&' to create a pointer to member
error C2672: 'std::async': no matching overloaded function found
error C2780: 'std::future<_Invoke_traits<void,decay<_Ty>::type,decay<_ArgTypes>::type...>::type> std::async(std::launch,_Fty &&,_ArgTypes &&...)': expects 3 arguments - 1 provided

Seems like MSVC is complaining that I have not used ptr->foo() but I am not sure.

What am I doing wrong?

Roy2511
  • 938
  • 1
  • 5
  • 22
  • 1
    The error is accurate. You are trying to call an instance function. But you provide no instance for it to use as `this`. How could it ever work? You probably want a lambda or `std::bind()` that will wrap both the instance and the function to call in a way that can be invoked later. Edit: as the answer linked in my next comment shows, `async` can do this. – underscore_d Jun 01 '20 at 09:26
  • Does this answer your question? [How to use std::async on a member function?](https://stackoverflow.com/questions/13669094/how-to-use-stdasync-on-a-member-function) – underscore_d Jun 01 '20 at 09:27
  • 1
    `std::async(&IG::FooFoo::foo, ptr.get());` or `std::async(&IG::FooFoo::foo, std::ref(*ptr))`. – Evg Jun 01 '20 at 09:29
  • @underscore_d and @Evg -- both give me ```error: ‘IG::CadDef IG::FooFoo::foo()’ is private within this context``` – Roy2511 Jun 01 '20 at 09:37
  • @Roy2511, you should make it `public` for this to work. – Evg Jun 01 '20 at 09:39
  • 1
    oh damnit, sorry – Roy2511 Jun 01 '20 at 09:40

2 Answers2

5

You can use a lambda like following, using a policy*

auto handle = std::async(std::launch::async, [&ptr](){
        return ptr->foo(); // Ofcourse make foo public in your snippet
});


auto res = handle.get();

*Not necessarily required

P0W
  • 46,614
  • 9
  • 72
  • 119
2

Async takes a function address as an argument, but it the function is a class-member function you have to bind it to the object which can invoke this function.

All functions (including methods) are moved to the code segment of the binary file. That's why the sizeof(T) equals to sum of sizeof of all class data-members (including a virtual table pointer (vptr) if exists).

class A {void method() }; can be represented as void method(A* a) {}

Knowing all this information you should bind the method with the object

int main()
{
    auto ptr = std::make_unique<IG::FooFoo>();
    std::future<IG::CadDef> resFut = std::async(&IG::FooFoo::foo, ptr.get());
    auto res = resFut.get();
    return 0;
}
Skident
  • 326
  • 1
  • 5
  • The 2nd paragraph seems to try to say there's only one copy of member function per class, hence the need to pass an instance to it when invoking. Is that right? I would only add that `std::bind`-like functors can also take a reference to instance, which doesn't matter much but is sometimes more convenient or just nicer to avoid pointers. – underscore_d Jun 01 '20 at 09:55
  • yes, that's totally right. Sure, std::bind or lambda could be used as well. – Skident Jun 01 '20 at 10:05
  • 1
    @underscore_d, and it should also be mentioned that such functors copy/move their parameters, so to pass a reference, you need to wrap it into `std::ref`. – Evg Jun 01 '20 at 10:17
  • `std::async` probably uses `std::bind` _et al._ under the hood so should accept refs too. Very good point about needing a `reference_wrapper` for functors that take args by value. – underscore_d Jun 01 '20 at 10:19