3

I've tried the following with VS, g++ and Clang and couldn't make rhyme or reason of any of the errors spewed out.

void foo() {}

auto f = bind(async, foo);

I suspect the errors may stem from the confusion on which async() to bind to, the one that takes a launch policy versus the one that doesn't... Or I have to explicitly give async() its template types (e.g. async<...>)? Either way, what's the proper way to write the statement above?

Edit:

Thanks for your suggestions guys, but none of the following works (with any compiler):

bind(async<decltype(foo)>, foo);

bind(async<void (*)()>, foo);

bind(async<function<void ()> >, foo);
screwnut
  • 1,367
  • 7
  • 26

2 Answers2

2

You must give async the template parameters. There isn't just one async to bind to. There is one for each instantiation of the function template.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
2

std::async is not only a template, but it's also overloaded. You'll need to select not only the template you want, but also the overload.

 typedef decltype(&foo) foo_type;
 typedef std::result_of<foo_type()>::type foo_rettype;

 auto chosen_async=
   static_cast<std::future<foo_rettype> (*)(foo_type && )>
     (&std::async<foo_type>);

Unfortunately, std::bind doesn't seem to allow binding functions taking rvalue references. So just writing std::bind(chosen_async, &foo) still won't work. A workaround for this problem is discussed in Is there a reference_wrapper<> for rvalue references?:

template<typename T> struct adv { 
  T t; 
  explicit adv(T &&t):t(std::forward<T>(t)) {} 
  template<typename ...U> T &&operator()(U &&...) { 
    return std::forward<T>(t); 
  } 
}; 

template<typename T> adv<T> make_adv(T &&t) { 
  return adv<T>{std::forward<T>(t)}; 
}

namespace std { 
  template<typename T> 
  struct is_bind_expression< adv<T> > : std::true_type {}; 
} 

We'd be done by saying std::bind(chosen_async, make_adv(std::move(&foo))), except for one problem: You can't directly pass std::async one of our wrapper objects, and consequently std::result_of<...> (hence std::bind). can't deduce what chosen_async will return. So we explicitly state the return type:

auto async_bound=
    std::bind<std::future<foo_rettype>>(chosen_async, 
                                        make_adv(std::forward<foo_type>(&foo)));

Doing all of this seems enough to make GCC happy, at least: http://ideone.com/gapLs.


Of course, you could save yourself a ton of hassle with a lambda expression:

auto async_bound=[=]()->std::future<void> {return std::async(&foo);};
Community
  • 1
  • 1
Managu
  • 8,849
  • 2
  • 30
  • 36
  • It runs now. It's super ugly too. Did someone suggest just using a lambda expression? ;-) – Managu Jun 21 '12 at 06:57
  • @Managu Thanks for doing the hard work of investigation (and showing that it wasn't so simple as to "give it the template parameters"). Now, to tell you the truth, I was kinda of goofing off when I stumbled on that "problem". I don't have a "real world" need for this. I was trying to see if I could get to something like auto f = bind(async, foo, _1); f(11).get(); f(22).get(); (That's the compressed version). After your answer, I'm not sure it can be done elegantly... But, still, your answer may benefit someone later on. And that person could be you or me. :) – screwnut Jun 22 '12 at 20:12
  • @screwnut: I figured as much. And lambdas are still nicer: `auto fooasync=[=](int i)->decltype(async(&foo, i)) {return async(&foo, i);}` – Managu Jun 23 '12 at 01:25