Boost logo

Boost :

Subject: Re: [boost] [utility][thread] result_of - erroneous result type from a C++11 lambda
From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2013-06-17 14:06:52


On Jun 17, 2013, at 1:28 PM, Klaim - Joël Lamotte <mjklaim_at_[hidden]> wrote:

> On Tue, Apr 2, 2013 at 7:16 PM, Vicente J. Botet Escriba <
> vicente.botet_at_[hidden]> wrote:
>
>> I've started to use C++11 lambda functions with Boost.Thread.
>>
>> The following works with clang-3.2
>>
>> boost::future<int> f1 = boost::async( []() -> int {return 123;} );
>>
>>
>> But it fails with gcc-4.6.2, 4.7.2 and 4.8.0
>>
>> ../example/lambda_future.cpp:**25:91: erreur: conversion from
>> ‘boost::future<void>’ to non-scalar type ‘boost::future<int>’ requested
>> boost::future<int> f1 = boost::async( []() -> int {return 123;} );
>>
>> The current implementation of boost::async uses boost::result_of to get
>> the result type of the callable parameter.
>>
>> Is this a know bug on boost::result_of or gcc compiler?
>>
>
>
> I'm seeing exactly the same behaviour in *VS2012 Update 2*.
> I'm using Boost 1.54.0 beta *r84748*
>
> To be more precise:
>
> 1) I first was just using boost::future and tried to use the new .then(),
> here is a full repro:
>
>
> #include <boost/thread/future.hpp>
>
> auto ft = boost::async( []{ return 42; } ).then( []( boost::future<int> r
> ){ return 666; } );
>
>
> This fails because boost::async() returned a future<void> instead of a
> future<int>.
> I suspect the then() call to have the same problem.
> I can provide the full error log but I think it's not that useful.
>
> 2) Just to be sure I tried this full test:
>
> #include <boost/thread/future.hpp>
>
> int main()
> {
> auto ft = boost::async( []{ return 42; } );
> // SUCCEED:
> static_assert( std::is_same< decltype(ft), boost::future<void> >::value,
> "WTF???" );
> // FAILS:
> static_assert( std::is_same< decltype(ft), boost::future<int> >::value,
> "Not the expected type!" );
> }
>
>
> Both asserts confirm that I don't get what I want.
>
> 3) I remembered that there were some issues from usage of boost::result_of
> in Boost.Log, so to clarify the situation I setup the following full test:
>
>
>
> #include <boost/utility/result_of.hpp>
> #include <type_traits>
>
> int top() { return 42; }
> struct K
> {
> int operator()(){ return 42; }
>
> typedef int value_type;
> };
>
> auto F = []{ return 42; };
>
> int main()
> {
> // A: ALL SUCCEED
> static_assert( std::is_same< decltype(K()()), int >::value, "Not the
> expected type!" );
> static_assert( std::is_same< decltype(top()), int >::value, "Not the
> expected type!" );
> static_assert( std::is_same< decltype(F()), int >::value, "Not the expected
> type!" );
>
> // B: ALL SUCCEED
> static_assert( std::is_same< std::result_of<K()>::type, int >::value, "Not
> the expected type!" );
> static_assert( std::is_same< std::result_of<decltype(top)>::type, int
>> ::value, "Not the expected type!" );
> static_assert( std::is_same< std::result_of<decltype(F)()>::type, int
>> ::value, "Not the expected type!" );
>
>
> // C: ALL SUCCEED
> std::result_of<K()>::type a = K()();
> std::result_of<decltype(top)>::type b = top();
> std::result_of<decltype(F)()>::type c = F();
>
> // D: ALL FAILS
> static_assert( std::is_same< boost::result_of<K()>::type, int >::value,
> "Not the expected type!" );
> static_assert( std::is_same< boost::result_of<decltype(top)>::type, int
>> ::value, "Not the expected type!" );
> static_assert( std::is_same< boost::result_of<decltype(F)()>::type, int
>> ::value, "Not the expected type!" );
> // E: ALL FAILS
> boost::result_of<K()>::type d = K()(); // error C2182: 'd' : illegal use of
> type 'void'
> boost::result_of<decltype(top)>::type e = top(); // error C2182: 'e' :
> illegal use of type 'void'
> boost::result_of<decltype(F)()>::type f = F(); // error C2182: 'f' :
> illegal use of type 'void'
>
> }
>
>
>
> This shows clearly that:
>
> 1. boost::result_of don't behave like std::result_of on this platform (and
> from previous discussions, on other platforms too).
> 2. both std::result_of and decltype() provide the result I expect from
> reading documentations about these.
>
> So far I'm assuming that the problem really is from boost::result_of, but I
> might be wrong because the differences with std::result_of are not clear to
> me.
>
> ----
>
> Unfortunately this makes future.then() unusable if we expect return types.
> I don't know if it impacts other libraries (I suspect Boost.Log).
>
> Should I report a bug or is it known, already fixed or a misuse?

If I'm not mistaken, it looks like you are using the TR1 protocol with nullary functions. See the bullet point on nullary functions in the documentation.

http://www.boost.org/doc/libs/1_53_0/libs/utility/utility.htm#result_of_tr1_diff

TR1 cannot deduce the return type of nullary function objects. You probably either want to use std::result_of or boost::result_of with BOOST_RESULT_OF_USE_DECLTYPE defined. If you really must use TR1 there are workarounds for the nullary function issue discussed at the same bullet point at the link above, but these workarounds may not be applicable in your situation. In C++11, I would not recommend using TR1 unless you need it for backwards compatibility/portability to C++03, in which case you can't deduce return types for nullary function objects.

- Daniel


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk