Hello,
I noticed that result_of doesn't handle functors created by the Boost
Lambda Library. For example,
$ g++ -dumpversion
4.1.2
$ cat result_of_error.cpp
#include <boost/lambda/lambda.hpp>
#include <boost/utility/result_of.hpp>
using namespace boost;
template<class Functor, class Arg1, class Arg2>
void f(Functor const&, Arg1 const&, Arg2 const&)
{
typedef typename result_of<
Functor(Arg1, Arg2)
>::type result_type;
}
int main()
{
using namespace lambda;
int x = 0, y = 0;
f(ret<int>(_1 + _2), x, y);
}
$ g++ -I./boost result_of_error.cpp 2>&1 | perl gSTLFilt.pl
./boost/boost/utility/result_of.hpp:68: error: no class template named 'result'
in 'class boost::lambda::lambda_functor<
...
>'
...
$
Among Boost libraries, there are at least two ways for function
objects to expose return types that are dependent on the types of
their arguments.
1) result_of instructs users to expose a template result<F(ARG1, ..., ARGN)>.
2) Boost.Lambda instructs users to expose a template sig<tuple<ARG1,
..., ARGN>, and it also uses this convention internally.
It might be nice to unify these two approaches one day or perhaps
simplify the matter by implementing result_of in terms of the Boost
Typeof Library along the lines of Douglas Gregor's "Looking Ahead"
section in his 2003 paper,
http://tinyurl.com/2nf5ym. But I figure in
the mean time why not have result_of support both of the current
approaches? If the functor has a nested sig template use that,
otherwise try to use a nested result template.
There's one additional caveat for supporting lambda expressions. A
zero arity lambda functor expose its result type through the typedef
nullary_return_type. This can be handle in result_of by providing a
partial specialization of result_of_void_impl for the template class
lambda::lambda_functor.
The attached patch adds support for sig in functors and nullary lambda
functors. Apply with 'patch -p0 < djw_result_of.patch' from the boost
root directory. It depends on the has_template_xxx patch I submitted
previously (
http://tinyurl.com/35x5z5).
Also, if has_template_xxx is unsupported for a particular compiler the
patch supplies a partial specialization of result_of_nested_result for
lambda::lambda_functor. That way at least lambda expressions can be
supported if not user defined functors that employ the Boost Lambda
Library's convention of specifying result types. I ran the Boost
Utility Library test suite and everthing passed. Let me know and I can
provide documentation and tests.
Thanks!
Daniel Walker
Index: boost/utility/result_of.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/utility/result_of.hpp,v
retrieving revision 1.10
diff -d -u -r1.10 result_of.hpp
--- boost/utility/result_of.hpp 5 Mar 2007 15:25:15 -0000 1.10
+++ boost/utility/result_of.hpp 20 Mar 2007 15:09:20 -0000
@@ -15,8 +15,11 @@
#include <boost/preprocessor.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/mpl/has_xxx.hpp>
+#include <boost/mpl/has_template_xxx.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/bool.hpp>
+#include <boost/lambda/core.hpp>
+#include <boost/tuple/tuple.hpp>
#ifndef BOOST_RESULT_OF_NUM_ARGS
# define BOOST_RESULT_OF_NUM_ARGS 10
@@ -30,8 +33,10 @@
namespace detail {
BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type)
+BOOST_MPL_HAS_TEMPLATE_XXX_TRAIT_DEF(sig, 1)
template<typename F, typename FArgs, bool HasResultType> struct result_of_impl;
+template<typename F, typename FArgs> struct result_of_nested_result_impl;
template<typename F>
struct result_of_void_impl
@@ -51,6 +56,15 @@
typedef R type;
};
+// Support for zero arity functors from the Boost Lambda Library.
+template<typename F>
+struct result_of_void_impl<lambda::lambda_functor<F> >
+{
+ typedef typename lambda::lambda_functor<
+ F
+ >::nullary_return_type type;
+};
+
template<typename F, typename FArgs>
struct result_of_impl<F, FArgs, true>
{
@@ -63,15 +77,19 @@
template<typename F>
struct is_function_with_no_args<F(void)> : mpl::true_ {};
+template<typename F, typename FArgs, bool HasSigType>
+struct result_of_nested_result;
+
template<typename F, typename FArgs>
-struct result_of_nested_result : F::template result<FArgs>
+struct result_of_nested_result<F, FArgs, false>
+ : F::template result<FArgs>
{};
template<typename F, typename FArgs>
struct result_of_impl<F, FArgs, false>
: mpl::if_<is_function_with_no_args<FArgs>,
result_of_void_impl<F>,
- result_of_nested_result<F, FArgs> >::type
+ result_of_nested_result_impl<F, FArgs> >::type
{};
} // end namespace detail
Index: boost/utility/detail/result_of_iterate.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/utility/detail/result_of_iterate.hpp,v
retrieving revision 1.5
diff -d -u -r1.5 result_of_iterate.hpp
--- boost/utility/detail/result_of_iterate.hpp 24 Jan 2007 06:44:20 -0000 1.5
+++ boost/utility/detail/result_of_iterate.hpp 20 Mar 2007 15:09:20 -0000
@@ -22,6 +22,38 @@
BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
struct result_of<F(BOOST_RESULT_OF_ARGS)>
: detail::result_of_impl<F, F(BOOST_RESULT_OF_ARGS), (detail::has_result_type<F>::value)> {};
+
+namespace detail {
+template<typename F BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+ BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
+struct result_of_nested_result<F, F(BOOST_RESULT_OF_ARGS), true>
+ : F::template sig<tuple<BOOST_RESULT_OF_ARGS> >
+{};
+
+# if defined(BOOST_MPL_CFG_NO_HAS_TEMPLATE_XXX)
+// If has_template_xxx is not available partially specialize
+// result_of_nested_result for lambda::lambda_functor so that at least
+// lambda expressions are supported if not user defined functors that
+// employ the Boost Lambda Library's convention of specifying result
+// types.
+template<typename F BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+ BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
+struct result_of_nested_result<lambda::lambda_functor<F>,
+ lambda::lambda_functor<F>(BOOST_RESULT_OF_ARGS),
+ false>
+ : lambda::lambda_functor<F>::template sig<tuple<BOOST_RESULT_OF_ARGS> >
+{};
+# endif // BOOST_MPL_CFG_NO_HAS_TEMPLATE_XXX
+
+template<typename F BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+ BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
+struct result_of_nested_result_impl<F, F(BOOST_RESULT_OF_ARGS)>
+ : result_of_nested_result<
+ F, F(BOOST_RESULT_OF_ARGS),
+ has_template_sig<F, tuple<BOOST_RESULT_OF_ARGS> >::value
+ >
+{};
+} // end namespace detail
#endif
#undef BOOST_RESULT_OF_ARGS
_______________________________________________
Unsubscribe & other changes:
http://lists.boost.org/mailman/listinfo.cgi/boost