From b4dee80e617283c88c95b7f72cda2aa2807c0100 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 7 Mar 2010 12:08:00 +0000 Subject: [PATCH] Merge various result_of changes. - [42234] Reduce header dependencies, from Shunsuke Sogame. Fixes #1535 - [45256] result_of implementation that makes use of C++0x decltype, from Daniel Walker. Fixes #862. - [48620] Fix result_of to work with const-qualified function pointers. Fixes #1310 - [60052] Remove use of deprecated config macro in result_of. [SVN r60289] --- .../utility/detail/result_of_iterate.hpp | 54 +++++++- include/boost/utility/result_of.hpp | 17 ++- test/result_of_test.cpp | 131 ++++++++++++++++-- utility.htm | 8 +- 4 files changed, 194 insertions(+), 16 deletions(-) diff --git a/include/boost/utility/detail/result_of_iterate.hpp b/include/boost/utility/detail/result_of_iterate.hpp index 41616c3..7b09435 100644 --- a/include/boost/utility/detail/result_of_iterate.hpp +++ b/include/boost/utility/detail/result_of_iterate.hpp @@ -10,6 +10,47 @@ # error Boost result_of - do not include this file! #endif +#if !defined(BOOST_NO_DECLTYPE) + +// As of N2588, C++0x result_of only supports function call +// expressions of the form f(x). This precludes support for member +// function pointers, which are invoked with expressions of the form +// o->*f(x). This implementation supports both. +template +struct result_of + : mpl::if_< + mpl::or_< is_pointer, is_member_function_pointer > + , detail::result_of_impl< + typename remove_cv::type, + typename remove_cv::type(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)), false + > + , detail::result_of_decltype_impl< + F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)) + > + >::type +{}; + +namespace detail { + +# define BOOST_RESULT_OF_STATIC_MEMBERS(z, n, _) \ + static T ## n t ## n; \ + /**/ + +template +class result_of_decltype_impl +{ + static F f; + BOOST_PP_REPEAT(BOOST_PP_ITERATION(), BOOST_RESULT_OF_STATIC_MEMBERS, _) +public: + typedef decltype(f(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),t))) type; +}; + +} // namespace detail + +#else // defined(BOOST_HAS_DECLTYPE) + // CWPro8 requires an argument in a function type specialization #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3002)) && BOOST_PP_ITERATION() == 0 # define BOOST_RESULT_OF_ARGS void @@ -21,11 +62,22 @@ template struct result_of - : boost::detail::result_of_impl::value)> {}; + : mpl::if_< + mpl::or_< is_pointer, is_member_function_pointer > + , boost::detail::result_of_impl< + typename remove_cv::type, + typename remove_cv::type(BOOST_RESULT_OF_ARGS), + (boost::detail::has_result_type::value)> + , boost::detail::result_of_impl< + F, + F(BOOST_RESULT_OF_ARGS), + (boost::detail::has_result_type::value)> >::type { }; #endif #undef BOOST_RESULT_OF_ARGS +#endif // defined(BOOST_HAS_DECLTYPE) + #if BOOST_PP_ITERATION() >= 1 namespace detail { diff --git a/include/boost/utility/result_of.hpp b/include/boost/utility/result_of.hpp index e35e098..78168fa 100644 --- a/include/boost/utility/result_of.hpp +++ b/include/boost/utility/result_of.hpp @@ -10,13 +10,18 @@ #define BOOST_RESULT_OF_HPP #include -#include -#include -#include +#include +#include +#include +#include #include #include #include #include +#include +#include +#include +#include #ifndef BOOST_RESULT_OF_NUM_ARGS # define BOOST_RESULT_OF_NUM_ARGS 10 @@ -32,6 +37,7 @@ namespace detail { BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type) template struct result_of_impl; +template struct result_of_decltype_impl; template struct result_of_void_impl @@ -51,6 +57,11 @@ struct result_of_void_impl typedef R type; }; +// Determine the return type of a function pointer or pointer to member. +template +struct result_of_pointer + : result_of_impl::type, FArgs, false> { }; + template struct result_of_impl { diff --git a/test/result_of_test.cpp b/test/result_of_test.cpp index 10f3410..73dc757 100644 --- a/test/result_of_test.cpp +++ b/test/result_of_test.cpp @@ -11,35 +11,101 @@ #include #include -struct int_result_type { typedef int result_type; }; +struct int_result_type +{ + typedef int result_type; + result_type operator()(float); +}; struct int_result_of { template struct result { typedef int type; }; + result::type operator()(double); + result::type operator()(double) const; + result::type operator()(); + result::type operator()() volatile; }; -struct int_result_type_and_float_result_of +struct int_result_type_and_float_result_of_and_char_return { typedef int result_type; template struct result { typedef float type; }; + char operator()(char); }; template -struct int_result_type_template { typedef int result_type; }; +struct int_result_type_template +{ + typedef int result_type; + result_type operator()(float); +}; template struct int_result_of_template { template struct result; template struct result { typedef int type; }; + typename result(double)>::type operator()(double); + typename result(double)>::type operator()(double) const; + typename result(double)>::type operator()(); + typename result(double)>::type operator()() volatile; }; template -struct int_result_type_and_float_result_of_template +struct int_result_type_and_float_result_of_and_char_return_template { typedef int result_type; template struct result; template struct result { typedef float type; }; + char operator()(char); +}; + +struct result_of_member_function_template +{ + template struct result; + + template struct result { typedef That type; }; + template typename result::type operator()(T); + + template struct result { typedef const That type; }; + template typename result::type operator()(T) const; + + template struct result { typedef volatile That type; }; + template typename result::type operator()(T) volatile; + + template struct result { typedef const volatile That type; }; + template typename result::type operator()(T) const volatile; + + template struct result { typedef That & type; }; + template typename result::type operator()(T &, T); + + template struct result { typedef That const & type; }; + template typename result::type operator()(T const &, T); + + template struct result { typedef That volatile & type; }; + template typename result::type operator()(T volatile &, T); + + template struct result { typedef That const volatile & type; }; + template typename result::type operator()(T const volatile &, T); +}; + +struct no_result_type_or_result_of +{ + int operator()(double); + short operator()(double) const; + unsigned int operator()(); + unsigned short operator()() volatile; + const unsigned short operator()() const volatile; +}; + +template +struct no_result_type_or_result_of_template +{ + int operator()(double); + short operator()(double) const; + unsigned int operator()(); + unsigned short operator()() volatile; + const unsigned short operator()() const volatile; }; struct X {}; @@ -60,16 +126,37 @@ int main() BOOST_STATIC_ASSERT((is_same::type, int>::value)); BOOST_STATIC_ASSERT((is_same::type, int>::value)); - BOOST_STATIC_ASSERT((is_same::type, void>::value)); BOOST_STATIC_ASSERT((is_same::type, int>::value)); - BOOST_STATIC_ASSERT((is_same::type, void>::value)); - BOOST_STATIC_ASSERT((is_same::type, int>::value)); BOOST_STATIC_ASSERT((is_same(float)>::type, int>::value)); BOOST_STATIC_ASSERT((is_same(double)>::type, int>::value)); - BOOST_STATIC_ASSERT((is_same(void)>::type, void>::value)); BOOST_STATIC_ASSERT((is_same(double)>::type, int>::value)); + + // Prior to decltype, result_of could not deduce the return type + // nullary function objects unless they exposed a result_type. +#if defined(BOOST_HAS_DECLTYPE) + BOOST_STATIC_ASSERT((is_same::type, int>::value)); + BOOST_STATIC_ASSERT((is_same::type, int>::value)); + BOOST_STATIC_ASSERT((is_same(void)>::type, int>::value)); + BOOST_STATIC_ASSERT((is_same(void)>::type, int>::value)); +#else + BOOST_STATIC_ASSERT((is_same::type, void>::value)); + BOOST_STATIC_ASSERT((is_same::type, void>::value)); + BOOST_STATIC_ASSERT((is_same(void)>::type, void>::value)); BOOST_STATIC_ASSERT((is_same(void)>::type, void>::value)); - BOOST_STATIC_ASSERT((is_same(char)>::type, int>::value)); +#endif + + // Prior to decltype, result_of ignored a nested result<> if + // result_type was defined. After decltype, result_of deduces the + // actual return type of the function object, ignoring both + // result<> and result_type. +#if defined(BOOST_HAS_DECLTYPE) + BOOST_STATIC_ASSERT((is_same::type, char>::value)); + BOOST_STATIC_ASSERT((is_same(char)>::type, char>::value)); +#else + BOOST_STATIC_ASSERT((is_same::type, int>::value)); + BOOST_STATIC_ASSERT((is_same(char)>::type, int>::value)); +#endif + BOOST_STATIC_ASSERT((is_same::type, int>::value)); BOOST_STATIC_ASSERT((is_same::type, int>::value)); BOOST_STATIC_ASSERT((is_same::type, int>::value)); @@ -81,5 +168,31 @@ int main() BOOST_STATIC_ASSERT((is_same::type, int>::value)); BOOST_STATIC_ASSERT((is_same::type, int>::value)); + BOOST_STATIC_ASSERT((is_same::type, double>::value)); + BOOST_STATIC_ASSERT((is_same::type, const double>::value)); + BOOST_STATIC_ASSERT((is_same::type, volatile double>::value)); + BOOST_STATIC_ASSERT((is_same::type, const volatile double>::value)); + BOOST_STATIC_ASSERT((is_same::type, int &>::value)); + BOOST_STATIC_ASSERT((is_same::type, int const &>::value)); + BOOST_STATIC_ASSERT((is_same::type, int volatile &>::value)); + BOOST_STATIC_ASSERT((is_same::type, int const volatile &>::value)); + + typedef int (*pf_t)(int); + BOOST_STATIC_ASSERT((is_same::type, int>::value)); + BOOST_STATIC_ASSERT((is_same::type,int>::value)); + +#if defined(BOOST_HAS_DECLTYPE) + BOOST_STATIC_ASSERT((is_same::type, int>::value)); + BOOST_STATIC_ASSERT((is_same::type, unsigned int>::value)); + BOOST_STATIC_ASSERT((is_same::type, short>::value)); + BOOST_STATIC_ASSERT((is_same::type, unsigned short>::value)); + BOOST_STATIC_ASSERT((is_same::type, const unsigned short>::value)); + BOOST_STATIC_ASSERT((is_same(double)>::type, int>::value)); + BOOST_STATIC_ASSERT((is_same(void)>::type, unsigned int>::value)); + BOOST_STATIC_ASSERT((is_same(double)>::type, short>::value)); + BOOST_STATIC_ASSERT((is_same(void)>::type, unsigned short>::value)); + BOOST_STATIC_ASSERT((is_same(void)>::type, const unsigned short>::value)); +#endif + return 0; } diff --git a/utility.htm b/utility.htm index eff847d..d4c7205 100644 --- a/utility.htm +++ b/utility.htm @@ -154,11 +154,13 @@ void f() { ...,tN). The implementation permits the type F to be a function pointer, function reference, member function pointer, or class - type. When F is a class type with a - member type result_type, + type.

If your compiler does not support + decltype, then when F is a + class type with a member type result_type, result_of<F(T1, T2, ..., TN)> is - F::result_type. Otherwise, + F::result_type. When F + does not contain result_type, result_of<F(T1, T2, ..., TN)> is F::result<F(T1, T2, ..., TN)>::type when