4

I am getting unexpected results from boost::async() (Boost 1.56, Windows: VS2010 and VS2012).

#include <boost/thread/future.hpp>
...
auto func = [](){ return 123; };
auto boostFut = boost::async(func);
// boostFut = 42; // intentional error to reveal deduced type in compilation error

For some reason boostFut is deduced as boost::unique_future<void> instead of boost::unique_future<int>.

What am I doing wrong?

Note: on VS2012, if I used std::async(func) instead of boost::async(func) it does work as expected and the future type is deduced as int.

Adi Shavit
  • 16,743
  • 5
  • 67
  • 137
  • Version of `boost` is useful. Oh, and sometimes boost functions want a `result_type` typedef in the passed in function object. – Yakk - Adam Nevraumont Nov 30 '14 at 16:41
  • As stated above: Boost 1.56. Can you elaborate on the `result_type` suggestion? The problem still remains even if I explicitly define: `boost::unique_future boostFut = ...` in this case the `asyn()` assignment fails to compile. – Adi Shavit Nov 30 '14 at 16:43
  • Sorry missed that. I know that some of the boost function adapters have required that the result type be explicit in the passed in object, or at the least will fall back on that if they cannot solve the problem. Does your problem go away with a function pointer? a `struct foo { typedef int result_type; int operator()() const { return 42; };`? A `foo` without the `result_type`? – Yakk - Adam Nevraumont Nov 30 '14 at 16:46
  • 2
    @AdiShavit try adding `#define BOOST_RESULT_OF_USE_DECLTYPE` before you include boost libraries – Piotr Skotnicki Nov 30 '14 at 16:48
  • @PiotrS.: That did the trick! Where is that documented? Write it up as an answer and I'll mark it. – Adi Shavit Nov 30 '14 at 18:23

1 Answers1

4

boost::async needs to determine the resultant type of the argument functor's call. In order to do that, Boost uses its own boost::result_of<T> class template implementation. That is, async declaration looks as below:

template <class F>
boost::future<typename boost::result_of<typename boost::decay<F>::type()>::type>
async(F f);

Depending on the compiler's capabilities/boost's configuration, boost::result_of<T> trait may work in one of the two ways:

  1. Use decltype() from the call expression.
  2. Look for a nested result_type typedef within F or a nested result<T> class template within F (if a number of the functor's arguments is greater than zero, as overloads may exist).

If the latter approach (2) is used, neither of the aforementioned alternatives are applicable for lambda's type, therefore Boost ends up with default assumption deducing void as a return type.

To make sure your Boost implementation will use decltype() operator (that works for lambda's call expressions fine), you need to prepend a define prior to Boost headers inclusion:

#define BOOST_RESULT_OF_USE_DECLTYPE

or add this define to boost/config/user.hpp file.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160