Opened 10 years ago
Last modified 10 years ago
#7343 new Feature Requests
Extend result_of to work with SFINAE
Reported by: | Daniel Walker | Owned by: | Daniel Walker |
---|---|---|---|
Milestone: | To Be Determined | Component: | result_of |
Version: | Boost 1.52.0 | Severity: | Problem |
Keywords: | result_of, decltype, SFINAE | Cc: |
Description
In response to a problem first identified by Joel de Guzman:
http://thread.gmane.org/gmane.comp.lib.boost.devel/233752/focus=233934
When BOOST_RESULT_OF_USE_DECLTYPE is defined, the attached patch makes the expression result_of<Fn( ArgTypes ...)>::type not well formed when the expression decltype(INVOKE(declval< Fn >(), declval< ArgTypes >()...)) is not well formed, but does not break SFINAE when used as the return type of a function overload.
Attachments (2)
Change History (28)
by , 10 years ago
Attachment: | djw_result_of_sfinae.patch added |
---|
by , 10 years ago
Attachment: | ean_result_of_sfinae.patch added |
---|
simpler patch, tested with clang-trunk
comment:1 by , 10 years ago
Daniel, I've attached a much simpler, lighter-weight patch. However, both of our patches are incomplete because of how result_of
is defined:
// Uses declval following N3225 20.7.7.6 when F is not a pointer. template<typename F BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)> struct result_of<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T))> : mpl::if_< is_member_function_pointer<F> , detail::tr1_result_of_impl< typename remove_cv<F>::type, typename remove_cv<F>::type(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)), false > , detail::cpp0x_result_of_impl< F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)) > >::type {};
If F
is a member function pointer, the first branch of the mpl::if_
gets taken, and no clever SFINAE guards detail::tr1_result_of_impl
.
But to a first approximation, I think this is good enough for 1.52. I tested my patch with clang-trunk, but not the most recent stable release, and not with msvc-11, which I'm downloading now. If you have access to those and want to get a jump on things, that'd be great. I'd like to get this change in to trunk ASAP so we have time to merge to release for 1.52.
Thanks for your work on this.
comment:2 by , 10 years ago
Thanks Eric. Your patch looks reasonable, and I like the simplifications. I'll test on clang 2.1 later today and assuming all's well I'll check your patch into trunk. I'd also like to see this in the 1.52 release. To my knowledge this is not a breaking change, i.e. enabling SFINAE doesn't invalidate any previously valid code, so we should be good to go.
comment:3 by , 10 years ago
Sadly, my patch doesn't work with msvc-11, but yours does. Unfortunately, yours has heavier TMP overhead. The best solution, IMO, would be to use yours for msvc-11 and use mine in other cases, assuming clang 3.1 can handle it. Thoughts?
comment:4 by , 10 years ago
For the record, here is the msvc bug that is blocking the simpler implementation from working:
comment:5 by , 10 years ago
I tested both versions (in a C++11 mode with BOOST_RESULT_OF_USE_DECLTYPE
)
and got the same results:
- gcc 4.3-4.4: compilation error on sfinae_test
- gcc 4.5-4.7, 4.8 (experimental): OK
- clang 2.8-3.1, 3.2 (trunk): OK
I think gcc 4.3-4.4 had incomplete support of "SFINAE for expressions"
(though BOOST_NO_SFINAE_EXPR
is not defined on gcc 4.4).
comment:6 by , 10 years ago
I combined the two patches so that the thin implementation is the default and the is_callable implementation is a workaround for MSVC tested at 1700. I tested on clang 3.2 and gcc 4.7 with BOOST_RESULT_OF_USE_DECLTYPE and can corroborate Michel's results. Eric could you test on MSVC one more time? If everything is OK, I think its ready to merge to release.
comment:7 by , 10 years ago
I tested r80605 (in a C++11 mode with BOOST_RESULT_OF_USE_DECLTYPE). The test results are the same as above:
- gcc 4.3-4.4: compilation error on sfinae_test
- gcc 4.5-4.7, 4.8 (experimental): OK
- clang 2.8-3.1, 3.2 (trunk): OK
comment:8 by , 10 years ago
Tests pass on msvc 8-11. That does *not* mean we're ready to merge to release, though. It means we're ready to wait and see what crops up in the trunk regression reports. :-)
comment:11 by , 10 years ago
Eric, did you test on msvc 10 with BOOST_RESULT_OF_USE_DECLTYPE
?
(In other word, does the "Too-eager instantiation in class template partial
specialization" bug happen only on msvc 11?)
comment:12 by , 10 years ago
Good question. No, it doesn't compile on msvc 10 in that configuration. I'll look into it.
Regardless, I took the liberty of merging all the outstanding result_of changes to release, since the trunk tests looked no worse than before. When I get a handle on the msvc regression, I'll merge that too. For reference, the release changeset is [80621].
comment:13 by , 10 years ago
Changeset [80636] on trunk changes the workaround for msvc and extends it to work for all compilers that don't do extended-sfinae-for-expressions. All the tests should pass now, even on gcc 4.3-4.4. Michel, can you give it a shot?
comment:14 by , 10 years ago
Works on gcc 4.4. Nice! However, BOOST_NO_SFINAE_EXPR does not appear to be defined for 4.4. boost/config/gcc.hpp has
(GNUC == 4 && GNUC_MINOR < 4) |
# define BOOST_NO_SFINAE_EXPR #endif
Should that be GNUC_MINOR < 5?
comment:15 by , 10 years ago
I don't know. What's your reason for thinking that BOOST_NO_SFINAE_EXPR
should be defined for gcc 4.4?
comment:16 by , 10 years ago
I don't know either, but you ifdefed the workaround with BOOST_NO_SFINAE_EXPR. I had to define it in order to test your changes, which do work on gcc 4.4. The tests fail on gcc 4.4 without the workaround.
comment:17 by , 10 years ago
First, I did the following
- Remove
BOOST_RESULT_OF_USE_DECLTYPE
guard forsfinae_test
inresult_of_test.cpp
. - Make gcc 4.4 in a C++11 mode (with
BOOST_RESULT_OF_USE_DECLTYPE
) follow theBOOST_NO_SFINAE_EXPR
branch.
Without applying 2, the test fails to compile on gcc 4.4 (in a C++11 mode BOOST_RESULT_OF_USE_DECLTYPE
).
Here are the test results.
- gcc 4.3 - 4.8 (in a C++03 mode): OK
- gcc 4.3 - 4.8 (in a C++11 mode): OK
- gcc 4.3 - 4.4 (in a C++11 mode + BOOST_RESULT_OF_USE_DECLTYPE): OK but with two warnings:
boost/utility/detail/result_of_iterate.hpp:100: warning: object of type 'volatile int&' will not be accessed in left-hand operand of comma
boost/utility/detail/result_of_iterate.hpp:100: warning: object of type 'const volatile int&' will not be accessed in left-hand operand of comma
- gcc 4.5 - 4.8 (in a C++11 mode + BOOST_RESULT_OF_USE_DECLTYPE): OK
- clang 2.8 - 3.2 (in a C++03 mode): OK
- clang 2.8 - 3.2 (in a C++11 mode): OK
- clang 2.8 - 3.2 (in a C++11 mode + BOOST_RESULT_OF_USE_DECLTYPE): OK
comment:18 by , 10 years ago
Full warning messages on gcc 4.3-4.4 (in a C++11 mode BOOST_RESULT_OF_USE_DECLTYPE
):
boost/utility/detail/result_of_iterate.hpp: In instantiation of 'const bool boost::detail::result_of_is_callable_2<result_of_member_function_template, volatile int&, int>::value': boost/utility/detail/result_of_iterate.hpp:101: instantiated from 'boost::detail::result_of_is_callable_2<result_of_member_function_template, volatile int&, int>' boost/utility/enable_if.hpp:47: instantiated from 'boost::lazy_enable_if<boost::detail::result_of_is_callable_2<result_of_member_function_template, volatile int&, int>, boost::detail::cpp0x_result_of_impl<result_of_member_function_template ()(volatile int&, int), false> >' boost/utility/result_of.hpp:118: instantiated from 'boost::detail::cpp0x_result_of_impl<result_of_member_function_template ()(volatile int&, int), true>' boost/utility/result_of.hpp:59: instantiated from 'boost::result_of<result_of_member_function_template ()(volatile int&, int)>' untitled:245: instantiated from here boost/utility/detail/result_of_iterate.hpp:100: warning: object of type 'volatile int&' will not be accessed in left-hand operand of comma boost/utility/detail/result_of_iterate.hpp: In instantiation of 'const bool boost::detail::result_of_is_callable_2<result_of_member_function_template, const volatile int&, int>::value': boost/utility/detail/result_of_iterate.hpp:101: instantiated from 'boost::detail::result_of_is_callable_2<result_of_member_function_template, const volatile int&, int>' boost/utility/enable_if.hpp:47: instantiated from 'boost::lazy_enable_if<boost::detail::result_of_is_callable_2<result_of_member_function_template, const volatile int&, int>, boost::detail::cpp0x_result_of_impl<result_of_member_function_template ()(const volatile int&, int), false> >' boost/utility/result_of.hpp:118: instantiated from 'boost::detail::cpp0x_result_of_impl<result_of_member_function_template ()(const volatile int&, int), true>' boost/utility/result_of.hpp:59: instantiated from 'boost::result_of<result_of_member_function_template ()(const volatile int&, int)>' untitled:246: instantiated from here boost/utility/detail/result_of_iterate.hpp:100: warning: object of type 'const volatile int&' will not be accessed in left-hand operand of comma
comment:19 by , 10 years ago
In the above warnings, untitled:***
means result_of_test.cpp:***
. Sorry about that.
comment:20 by , 10 years ago
Changeset [80654] applies the workaround to gcc-4.4 also. Can you give it a shot? And how do I suppress errors on gcc?
EDIT: How do I suppress *WARNINGS* on gcc?
comment:21 by , 10 years ago
gcc has
#pragma GCC diagnostic ignored "-Wxxxx"
but, before gcc 4.6, the following is not supported.
#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wxxxx" #pragma GCC diagnostic pop
So we cannot restore the user's warning conditions.
Another way to disable warnings is add
#pragma GCC system_header
Adding this pragma into result_of.hpp
or result_of_iterate.hpp
removes the warning.
comment:22 by , 10 years ago
Warnings suppressed in changeset [80655] on gcc. Thanks for all the work Eric. The users will appreciate it! And thanks for the help Michel.
comment:23 by , 10 years ago
I tested r80655 on gcc and clang and it works fine.
Daniel, I think
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 5) && defined(BOOST_RESULT_OF_USE_DECLTYPE) #pragma GCC system_header #endif
would be safer for the future development.
comment:24 by , 10 years ago
I found a workaround for the gcc warnings in code. Changeset [80656] makes the change and removes the #pragma GCC system_header
.
comment:25 by , 10 years ago
r80656 works fine on gcc and clang. Thanks Eric and Daniel for all the work!
comment:26 by , 10 years ago
Component: | utility → result_of |
---|
updated patch incorporating suggestions from Michel Morin