Re: [boost] [utility][thread] result_of - erroneous result type from a C++11 lambda
On Tue, Apr 2, 2013 at 7:16 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> 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
::value, "Not the expected type!" ); static_assert( std::is_same< std::result_of
::type, int ::value, "Not the expected type!" );
// C: ALL SUCCEED
std::result_of
::value, "Not the expected type!" ); static_assert( std::is_same< boost::result_of
::type, int ::value, "Not the expected type!" ); // E: ALL FAILS boost::result_of ::type d = K()(); // error C2182: 'd' : illegal use of type 'void' boost::result_of ::type e = top(); // error C2182: 'e' : illegal use of type 'void' boost::result_of ::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? Joel Lamotte
On Jun 17, 2013, at 1:28 PM, Klaim - Joël Lamotte
On Tue, Apr 2, 2013 at 7:16 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> 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
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
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
#include 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
::type, int >::value, "Not the expected type!" ); static_assert( std::is_same< std::result_of ::type, int ::value, "Not the expected type!" ); static_assert( std::is_same< std::result_of
::type, int ::value, "Not the expected type!" ); // C: ALL SUCCEED std::result_of
::type a = K()(); std::result_of ::type b = top(); std::result_of ::type c = F(); // D: ALL FAILS static_assert( std::is_same< boost::result_of
::type, int >::value, "Not the expected type!" ); static_assert( std::is_same< boost::result_of ::type, int ::value, "Not the expected type!" ); static_assert( std::is_same< boost::result_of
::type, int ::value, "Not the expected type!" ); // E: ALL FAILS boost::result_of ::type d = K()(); // error C2182: 'd' : illegal use of type 'void' boost::result_of ::type e = top(); // error C2182: 'e' : illegal use of type 'void' boost::result_of ::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_... 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
On Mon, Jun 17, 2013 at 8:06 PM, Daniel Walker
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_...
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.
In my own VS2012 code I use decltype exclusively. But that do not fix the problem for boost libraries themselves: Boost.Thread (future, async) apparently uses boost::result_of which makes the two first example I provide go wrong and makes both async and .then unusable. My understanding was that indeed these libraries would automatically use decltype() in the implementation if available, not tr1::result_of or something else. Is automatically BOOST_RESULT_OF_USE_DECLTYPE defined for VS2012? If not isn't it a bug? decltype is available whatever the compilation flags you use. Joel lamotte
On Jun 17, 2013, at 2:27 PM, Klaim - Joël Lamotte
On Mon, Jun 17, 2013 at 8:06 PM, Daniel Walker
wrote: 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_...
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.
In my own VS2012 code I use decltype exclusively.
But that do not fix the problem for boost libraries themselves: Boost.Thread (future, async) apparently uses boost::result_of which makes the two first example I provide go wrong and makes both async and .then unusable. My understanding was that indeed these libraries would automatically use decltype() in the implementation if available, not tr1::result_of or something else. Is automatically BOOST_RESULT_OF_USE_DECLTYPE defined for VS2012? If not isn't it a bug? decltype is available whatever the compilation flags you use.
BOOST_RESULT_OF_USE_DECLTYPE is automatically defined when BOOST_NO_CXX11_DECLTYPE_N3276 is not defined; i.e. it's only enabled by default when the compiler has fairly complete decltype support including N3276. As of Boost 1.53.0, it appears this is not the case for any version of Visual Studio. (See boost/config/compiler/visualc.hpp starting at line 224 for unsupported features.) I don't know if there's been any progress on that front from Microsoft, but as soon as N3276 is enabled in Boost's compiler config file, result_of will use decltype by default for that compiler. - Daniel
On Mon, Jun 17, 2013 at 9:07 PM, Daniel Walker
BOOST_RESULT_OF_USE_DECLTYPE is automatically defined when BOOST_NO_CXX11_DECLTYPE_N3276 is not defined; i.e. it's only enabled by default when the compiler has fairly complete decltype support including N3276. As of Boost 1.53.0, it appears this is not the case for any version of Visual Studio. (See boost/config/compiler/visualc.hpp starting at line 224 for unsupported features.) I don't know if there's been any progress on that front from Microsoft, but as soon as N3276 is enabled in Boost's compiler config file, result_of will use decltype by default for that compiler.
Would it be unrealistic to fallback on std::result_of for VS2012 versions only? It would fix most result_of bugs in Boost caused on this plateform. Joel Lamotte
Klaim - Joël Lamotte wrote:
Daniel Walker wrote:
BOOST_RESULT_OF_USE_DECLTYPE is automatically defined when BOOST_NO_CXX11_DECLTYPE_N3276 is not defined; i.e. it's only enabled by default when the compiler has fairly complete decltype support including N3276. As of Boost 1.53.0, it appears this is not the case for any version of Visual Studio. (See boost/config/compiler/visualc.hpp starting at line 224 for unsupported features.) I don't know if there's been any progress on that front from Microsoft, but as soon as N3276 is enabled in Boost's compiler config file, result_of will use decltype by default for that compiler.
Would it be unrealistic to fallback on std::result_of for VS2012 versions only? It would fix most result_of bugs in Boost caused on this plateform.
The following patch will allow your use case to work, I believe: https://svn.boost.org/trac/boost/ticket/7753 This has been discussed before, but I think your report is another data point indicating that users would prefer something that deduces correctly for all cases, even though it changes the deduction of a nullary function type from what TR1 would do. Nate
On Mon, Jun 17, 2013 at 10:09 PM, Nathan Crookston < nathan.crookston@gmail.com> wrote:
The following patch will allow your use case to work, I believe:
Thanks I've seen this but wasn't sure it could solve the problem. I'll try it.
This has been discussed before, but I think your report is another data point indicating that users would prefer something that deduces correctly for all cases, even though it changes the deduction of a nullary function type from what TR1 would do.
Indeed. Joel Lamotte
On Jun 17, 2013, at 4:09 PM, Nathan Crookston
Klaim - Joël Lamotte wrote:
Daniel Walker wrote:
BOOST_RESULT_OF_USE_DECLTYPE is automatically defined when BOOST_NO_CXX11_DECLTYPE_N3276 is not defined; i.e. it's only enabled by default when the compiler has fairly complete decltype support including N3276. As of Boost 1.53.0, it appears this is not the case for any version of Visual Studio. (See boost/config/compiler/visualc.hpp starting at line 224 for unsupported features.) I don't know if there's been any progress on that front from Microsoft, but as soon as N3276 is enabled in Boost's compiler config file, result_of will use decltype by default for that compiler.
Would it be unrealistic to fallback on std::result_of for VS2012 versions only? It would fix most result_of bugs in Boost caused on this plateform.
The following patch will allow your use case to work, I believe:
https://svn.boost.org/trac/boost/ticket/7753
This has been discussed before, but I think your report is another data point indicating that users would prefer something that deduces correctly for all cases, even though it changes the deduction of a nullary function type from what TR1 would do.
Hey Nate, when we last discussed your patch I believe you said you were going to upload a new version (with appropriate documentation, etc.) that would leave in place the current default behavior of result_of. Any progress? - Daniel
Hi Daniel, Daniel Walker wrote:
Nathan Crookston wrote:
The following patch will allow your use case to work, I believe:
https://svn.boost.org/trac/boost/ticket/7753
This has been discussed before, but I think your report is another data point indicating that users would prefer something that deduces correctly for all cases, even though it changes the deduction of a nullary function type from what TR1 would do.
Hey Nate, when we last discussed your patch I believe you said you were going to upload a new version (with appropriate documentation, etc.) that would leave in place the current default behavior of result_of. Any progress?
Yes, I intended (and still intend) to create a version which will did not automatically use the decltype fallback on g++ < 4.7 and VC10-11, but was accessible via a macro. I admit, I still disagree that making the user opt in just because it's not standardized is the best course of action -- we know there are a number of users like Joel that would like their lambdas to 'just work.' Users that want strict TR1, even if it produces results that are incorrect for the actual functors used (void return type for all nullary functors that don't just use result_type) seem unlikely to exist in the wild. I'd be more comfortable asking such users to define the USE_TR1 macro. However, I'll try to find time tomorrow, since I think providing the option is better than the current situation of 'decltype or nothing' (for lambdas) on those platforms. Thanks, Nate
I just upgraded to the last Boost revision but didn't see any change related to this. Will the patch be applied only in the next version? Anyway I will define BOOST_RESULT_OF_USE_DECLTYPE manually in my project CMake to make the result more predictable for me. Joel Lamotte
On Jun 27, 2013, at 7:26 PM, Klaim - Joël Lamotte
I just upgraded to the last Boost revision but didn't see any change related to this. Will the patch be applied only in the next version?
Anyway I will define BOOST_RESULT_OF_USE_DECLTYPE manually in my project CMake to make the result more predictable for me.
Yes, you should define BOOST_RESULT_OF_USE_DECLTYPE. As a general rule of thumb, the only time you should not define BOOST_RESULT_OF_USE_DECLTYPE is if you are working with C++03 code. In fact, on more compliant C++11 compilers (e.g. clang 3.1, gcc 4.8.1, msvc 12), decltype will be enabled by default. - Daniel
BOOST_RESULT_OF_USE_DECLTYPE is automatically defined when BOOST_NO_CXX11_DECLTYPE_N3276 is not defined; i.e. it's only enabled by default when the compiler has fairly complete decltype support including N3276. As of Boost 1.53.0, it appears this is not the case for any version of Visual Studio. (See boost/config/compiler/visualc.hpp starting at line 224 for unsupported features.) I don't know if there's been any progress on that front from Microsoft, but as soon as N3276 is enabled in Boost's compiler config file, result_of will use decltype by default for that compiler. According to the message http://boost.2283326.n4.nabble.com/Config-N3276-decltype-support-on-VC-11-td...,
17.06.2013 23:07, Daniel Walker пишет: this bug has been fixed in VC12 (i.e, Visual Studio 2013, right?). -- Best regards, Sergey Cheban
[Sergey Cheban]
According to the message http://boost.2283326.n4.nabble.com/Config-N3276-decltype-support-on-VC-11-td..., this bug has been fixed in VC12 (i.e, Visual Studio 2013, right?).
Correct. *Please* confirm that VS 2013 Preview works when it's released later this month. Stephan T. Lavavej Visual C++ Libraries Developer
participants (5)
-
Daniel Walker
-
Klaim - Joël Lamotte
-
Nathan Crookston
-
Sergey Cheban
-
Stephan T. Lavavej