diff --git a/include/boost/utility/detail/result_of_iterate.hpp b/include/boost/utility/detail/result_of_iterate.hpp index 41616c3..6f1b2b1 100644 --- a/include/boost/utility/detail/result_of_iterate.hpp +++ b/include/boost/utility/detail/result_of_iterate.hpp @@ -10,6 +10,46 @@ # error Boost result_of - do not include this file! #endif +#if defined(BOOST_HAS_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< + F, F(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 @@ -26,6 +66,8 @@ struct result_of #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 a5bac6f..07306d6 100644 --- a/include/boost/utility/result_of.hpp +++ b/include/boost/utility/result_of.hpp @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #ifndef BOOST_RESULT_OF_NUM_ARGS # define BOOST_RESULT_OF_NUM_ARGS 10 @@ -33,6 +36,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 diff --git a/test/result_of_test.cpp b/test/result_of_test.cpp index 10f3410..c6e91ea 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,27 @@ 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)); + +#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 9514188..1102d47 100644 --- a/utility.htm +++ b/utility.htm @@ -152,11 +152,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