From fcfcc42baf4b7c65a46c785e077bf374a680038f Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 9 Jun 2010 01:39:48 +0000 Subject: [PATCH] Enable using result_of with Boost.Lambda. Fixes #426. Fixes #864 [SVN r62627] --- .../boost/lambda/detail/function_adaptors.hpp | 158 ++++++++- .../lambda/detail/lambda_functor_base.hpp | 2 +- .../boost/lambda/detail/lambda_functors.hpp | 19 ++ .../lambda/detail/return_type_traits.hpp | 2 - test/Jamfile | 1 + test/bind_tests_advanced.cpp | 67 +++- test/result_of_tests.cpp | 314 ++++++++++++++++++ 7 files changed, 540 insertions(+), 23 deletions(-) create mode 100644 test/result_of_tests.cpp diff --git a/include/boost/lambda/detail/function_adaptors.hpp b/include/boost/lambda/detail/function_adaptors.hpp index c30cbc6..cfe3b07 100644 --- a/include/boost/lambda/detail/function_adaptors.hpp +++ b/include/boost/lambda/detail/function_adaptors.hpp @@ -12,25 +12,167 @@ #ifndef BOOST_LAMBDA_FUNCTION_ADAPTORS_HPP #define BOOST_LAMBDA_FUNCTION_ADAPTORS_HPP +#include "boost/mpl/has_xxx.hpp" +#include "boost/tuple/tuple.hpp" #include "boost/type_traits/same_traits.hpp" +#include "boost/type_traits/remove_reference.hpp" +#include "boost/utility/result_of.hpp" namespace boost { namespace lambda { +namespace detail { + +BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(has_template_sig, sig, 1, true) + +template +struct remove_references_from_elements { + typedef typename boost::tuples::cons< + typename boost::remove_reference::type, + typename remove_references_from_elements::type + > type; +}; + +template<> +struct remove_references_from_elements { + typedef boost::tuples::null_type type; +}; + +} + template struct function_adaptor { + typedef typename detail::remove_reference_and_cv::type plainF; + +#if !defined(BOOST_NO_RESULT_OF) + // Support functors that use the boost::result_of return type convention. + template + struct result_converter; + template + struct result_converter + : plainF::template sig< + typename detail::remove_references_from_elements::type + > + {}; + template + struct result_converter + : result_of + {}; + template + struct result_converter + : result_of::type) + > + {}; + template + struct result_converter + : result_of::type, + typename tuples::element<2, Tuple>::type) + > + {}; + template + struct result_converter + : result_of::type, + typename tuples::element<2, Tuple>::type, + typename tuples::element<3, Tuple>::type) + > + {}; + template + struct result_converter + : result_of::type, + typename tuples::element<2, Tuple>::type, + typename tuples::element<3, Tuple>::type, + typename tuples::element<4, Tuple>::type) + > + {}; + template + struct result_converter + : result_of::type, + typename tuples::element<2, Tuple>::type, + typename tuples::element<3, Tuple>::type, + typename tuples::element<4, Tuple>::type, + typename tuples::element<5, Tuple>::type) + > + {}; + template + struct result_converter + : result_of::type, + typename tuples::element<2, Tuple>::type, + typename tuples::element<3, Tuple>::type, + typename tuples::element<4, Tuple>::type, + typename tuples::element<5, Tuple>::type, + typename tuples::element<6, Tuple>::type) + > + {}; + template + struct result_converter + : result_of::type, + typename tuples::element<2, Tuple>::type, + typename tuples::element<3, Tuple>::type, + typename tuples::element<4, Tuple>::type, + typename tuples::element<5, Tuple>::type, + typename tuples::element<6, Tuple>::type, + typename tuples::element<7, Tuple>::type) + > + {}; + template + struct result_converter + : result_of::type, + typename tuples::element<2, Tuple>::type, + typename tuples::element<3, Tuple>::type, + typename tuples::element<4, Tuple>::type, + typename tuples::element<5, Tuple>::type, + typename tuples::element<6, Tuple>::type, + typename tuples::element<7, Tuple>::type, + typename tuples::element<8, Tuple>::type) + > + {}; + template + struct result_converter + : result_of::type, + typename tuples::element<2, Tuple>::type, + typename tuples::element<3, Tuple>::type, + typename tuples::element<4, Tuple>::type, + typename tuples::element<5, Tuple>::type, + typename tuples::element<6, Tuple>::type, + typename tuples::element<7, Tuple>::type, + typename tuples::element<8, Tuple>::type, + typename tuples::element<9, Tuple>::type) + > + {}; + // we do not know the return type off-hand, we must ask it from Func - template class sig { - typedef typename Args::head_type F; + // To sig we pass a cons list, where the head is the function object type + // itself (potentially cv-qualified) + // and the tail contains the types of the actual arguments to be passed + // to the function object. The arguments can be cv qualified + // as well. + template + struct sig + : result_converter< + Args + , tuples::length::value + , detail::has_template_sig::value + > + {}; +#else // BOOST_NO_RESULT_OF + + template class sig { typedef typename detail::remove_reference_and_cv::type plainF; public: - // To sig we pass a cons list, where the head is the function object type - // itself (potentially cv-qualified) - // and the tail contains the types of the actual arguments to be passed - // to the function object. The arguments can be cv qualified - // as well. - typedef typename plainF::template sig::type type; + typedef typename plainF::template sig< + typename detail::remove_references_from_elements::type + >::type type; }; +#endif template static RET apply(A1& a1) { diff --git a/include/boost/lambda/detail/lambda_functor_base.hpp b/include/boost/lambda/detail/lambda_functor_base.hpp index 5bd3c90..b084acd 100644 --- a/include/boost/lambda/detail/lambda_functor_base.hpp +++ b/include/boost/lambda/detail/lambda_functor_base.hpp @@ -383,7 +383,7 @@ public: \ \ template struct sig { \ typedef typename \ - detail::deduce_non_ref_argument_types::type rets_t; \ + detail::deduce_argument_types::type rets_t; \ public: \ typedef typename \ return_type_N_prot::type type; \ diff --git a/include/boost/lambda/detail/lambda_functors.hpp b/include/boost/lambda/detail/lambda_functors.hpp index 5187c7d..9b1b082 100644 --- a/include/boost/lambda/detail/lambda_functors.hpp +++ b/include/boost/lambda/detail/lambda_functors.hpp @@ -161,6 +161,25 @@ public: inherited::template sig::type nullary_return_type; + // Support for boost::result_of. + template struct result; + template + struct result { + typedef nullary_return_type type; + }; + template + struct result { + typedef typename sig >::type type; + }; + template + struct result { + typedef typename sig >::type type; + }; + template + struct result { + typedef typename sig >::type type; + }; + nullary_return_type operator()() const { return inherited::template call diff --git a/include/boost/lambda/detail/return_type_traits.hpp b/include/boost/lambda/detail/return_type_traits.hpp index d609e52..bf2394e 100644 --- a/include/boost/lambda/detail/return_type_traits.hpp +++ b/include/boost/lambda/detail/return_type_traits.hpp @@ -216,8 +216,6 @@ typedef typename // currently there are no protectable actions with > 2 args - // Note, that if there will be, lambda_functor_base will have to be - // changed to not get rid of references in Args elements template struct return_type_N_prot { typedef typename return_type_N::type type; diff --git a/test/Jamfile b/test/Jamfile index 4080eb3..7e1a5a7 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -30,5 +30,6 @@ test-suite lambda [ run operator_tests_simple.cpp ] [ run phoenix_control_structures.cpp ] [ run switch_construct.cpp ] + [ run result_of_tests.cpp ] [ run ret_test.cpp ] ; diff --git a/test/bind_tests_advanced.cpp b/test/bind_tests_advanced.cpp index a891f91..d696e49 100644 --- a/test/bind_tests_advanced.cpp +++ b/test/bind_tests_advanced.cpp @@ -2,6 +2,7 @@ // // Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) // Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// Copyright (C) 2010 Steven Watanabe // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -19,6 +20,9 @@ #include "boost/any.hpp" +#include "boost/type_traits/is_reference.hpp" +#include "boost/mpl/assert.hpp" +#include "boost/mpl/if.hpp" #include @@ -352,6 +356,55 @@ void test_break_const() BOOST_CHECK(i == 3); } +template +struct func { + template + struct sig { + typedef typename boost::tuples::element<1, Args>::type arg1; + // If the argument type is not the same as the expected type, + // return void, which will cause an error. Note that we + // can't just assert that the types are the same, because + // both const and non-const versions can be instantiated + // even though only one is ultimately used. + typedef typename boost::mpl::if_, + typename boost::remove_const::type, + void + >::type type; + }; + template + U operator()(const U& arg) const { + return arg; + } +}; + +void test_sig() +{ + int i = 1; + BOOST_CHECK(bind(func(), 1)() == 1); + BOOST_CHECK(bind(func(), _1)(static_cast(i)) == 1); + BOOST_CHECK(bind(func(), _1)(i) == 1); +} + +class base { +public: + virtual int foo() = 0; +}; + +class derived : public base { +public: + virtual int foo() { + return 1; + } +}; + +void test_abstract() +{ + derived d; + base& b = d; + BOOST_CHECK(bind(&base::foo, var(b))() == 1); + BOOST_CHECK(bind(&base::foo, *_1)(&b) == 1); +} + int test_main(int, char *[]) { test_nested_binds(); @@ -361,17 +414,7 @@ int test_main(int, char *[]) { test_const_parameters(); test_rvalue_arguments(); test_break_const(); + test_sig(); + test_abstract(); return 0; } - - - - - - - - - - - - diff --git a/test/result_of_tests.cpp b/test/result_of_tests.cpp new file mode 100644 index 0000000..9047f5b --- /dev/null +++ b/test/result_of_tests.cpp @@ -0,0 +1,314 @@ +// result_of_tests.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2010 Steven Watanabe +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include // see "Header Implementation Option" +#include +#include +#include +#include + +struct with_result_type { + typedef int result_type; + int operator()() const { return 0; } + int operator()(int) const { return 1; } + int operator()(int, int) const { return 2; } + int operator()(int, int, int) const { return 3; } + int operator()(int, int, int, int) const { return 4; } + int operator()(int, int, int, int, int) const { return 5; } + int operator()(int, int, int, int, int, int) const { return 6; } + int operator()(int, int, int, int, int, int, int) const { return 7; } + int operator()(int, int, int, int, int, int, int, int) const { return 8; } + int operator()(int, int, int, int, int, int, int, int, int) const { return 9; } +}; + +struct with_result_template_value { + template + struct result; + template + struct result { + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + + int operator()() const { return 0; } + int operator()(int) const { return 1; } + int operator()(int, int) const { return 2; } + int operator()(int, int, int) const { return 3; } + int operator()(int, int, int, int) const { return 4; } + int operator()(int, int, int, int, int) const { return 5; } + int operator()(int, int, int, int, int, int) const { return 6; } + int operator()(int, int, int, int, int, int, int) const { return 7; } + int operator()(int, int, int, int, int, int, int, int) const { return 8; } + int operator()(int, int, int, int, int, int, int, int, int) const { return 9; } +}; + +struct with_result_template_reference { + template + struct result; + template + struct result { + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + template + struct result { + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; + + int operator()() const { return 0; } + int operator()(int) const { return 1; } + int operator()(int, int) const { return 2; } + int operator()(int, int, int) const { return 3; } + int operator()(int, int, int, int) const { return 4; } + int operator()(int, int, int, int, int) const { return 5; } + int operator()(int, int, int, int, int, int) const { return 6; } + int operator()(int, int, int, int, int, int, int) const { return 7; } + int operator()(int, int, int, int, int, int, int, int) const { return 8; } + int operator()(int, int, int, int, int, int, int, int, int) const { return 9; } +}; + +template +typename boost::result_of::type apply0(F f) { + return f(); +} +template +typename boost::result_of::type apply1(F f, A a) { + return f(a); +} +template +typename boost::result_of::type apply2(F f, A a, B b) { + return f(a, b); +} +template +typename boost::result_of::type apply3(F f, A a, B b, C c) { + return f(a, b, c); +} + +using namespace boost::lambda; + +int test_main(int, char *[]) { + BOOST_CHECK(boost::lambda::bind(with_result_type())() == 0); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1)() == 1); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2)() == 2); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3)() == 3); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4)() == 4); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5)() == 5); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5, 6)() == 6); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5, 6, 7)() == 7); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5, 6, 7, 8)() == 8); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5, 6, 7, 8, 9)() == 9); + + // Nullary result_of fails + //BOOST_CHECK(boost::lambda::bind(with_result_template_value())() == 0); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1)() == 1); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2)() == 2); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3)() == 3); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4)() == 4); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5)() == 5); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5, 6)() == 6); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5, 6, 7)() == 7); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5, 6, 7, 8)() == 8); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5, 6, 7, 8, 9)() == 9); + + int one = 1, + two = 2, + three = 3, + four = 4, + five = 5, + six = 6, + seven = 7, + eight = 8, + nine = 9; + + // Nullary result_of fails + //BOOST_CHECK(boost::lambda::bind(with_result_template_reference())() == 0); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one))() == 1); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two))() == 2); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three))() == 3); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four))() == 4); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five))() == 5); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five), var(six))() == 6); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five), var(six), var(seven))() == 7); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five), var(six), var(seven), var(eight))() == 8); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five), var(six), var(seven), var(eight), var(nine))() == 9); + + // Check using result_of with lambda functors + //BOOST_CHECK(apply0(constant(0)) == 0); + BOOST_CHECK(apply1(_1, one) == 1); + BOOST_CHECK(apply1(_1, one) == 1); + BOOST_CHECK(apply1(_1, one) == 1); + BOOST_CHECK((apply2(_1 + _2, one, two) == 3)); + BOOST_CHECK((apply2(_1 + _2, one, two) == 3)); + BOOST_CHECK((apply2(_1 + _2, one, two) == 3)); + BOOST_CHECK((apply3(_1 + _2 + _3, one, two, three) == 6)); + BOOST_CHECK((apply3(_1 + _2 + _3, one, two, three) == 6)); + BOOST_CHECK((apply3(_1 + _2 + _3, one, two, three) == 6)); + + return 0; +}