| // return_type_traits.hpp -- Boost Lambda Library --------------------------- |
| |
| // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) |
| // |
| // 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 |
| |
| |
| #ifndef BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP |
| #define BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP |
| |
| #include "ndnboost/mpl/has_xxx.hpp" |
| |
| #include <cstddef> // needed for the ptrdiff_t |
| |
| namespace ndnboost { |
| namespace lambda { |
| |
| using ::ndnboost::type_traits::ice_and; |
| using ::ndnboost::type_traits::ice_or; |
| using ::ndnboost::type_traits::ice_not; |
| |
| // Much of the type deduction code for standard arithmetic types |
| // from Gary Powell |
| |
| // different arities: |
| template <class Act, class A1> struct return_type_1; // 1-ary actions |
| template <class Act, class A1, class A2> struct return_type_2; // 2-ary |
| template <class Act, class Args> struct return_type_N; // >3- ary |
| |
| template <class Act, class A1> struct return_type_1_prot; |
| template <class Act, class A1, class A2> struct return_type_2_prot; // 2-ary |
| template <class Act, class A1> struct return_type_N_prot; // >3-ary |
| |
| |
| namespace detail { |
| |
| template<class> class return_type_deduction_failure {}; |
| |
| // In some cases return type deduction should fail (an invalid lambda |
| // expression). Sometimes the lambda expression can be ok, the return type |
| // just is not deducible (user defined operators). Then return type deduction |
| // should never be entered at all, and the use of ret<> does this. |
| // However, for nullary lambda functors, return type deduction is always |
| // entered, and there seems to be no way around this. |
| |
| // (the return type is part of the prototype of the non-template |
| // operator()(). The prototype is instantiated, even though the body |
| // is not.) |
| |
| // So, in the case the return type deduction should fail, it should not |
| // fail directly, but rather result in a valid but wrong return type, |
| // causing a compile time error only if the function is really called. |
| |
| |
| |
| } // end detail |
| |
| |
| |
| // return_type_X_prot classes -------------------------------------------- |
| // These classes are the first layer that gets instantiated from the |
| // lambda_functor_base sig templates. It will check whether |
| // the action is protectable and one of arguments is "protected" or its |
| // evaluation will otherwise result in another lambda functor. |
| // If this is a case, the result type will be another lambda functor. |
| |
| // The arguments are always non-reference types, except for comma action |
| // where the right argument can be a reference too. This is because it |
| // matters (in the builtin case) whether the argument is an lvalue or |
| // rvalue: int i; i, 1 -> rvalue; 1, i -> lvalue |
| |
| template <class Act, class A> struct return_type_1_prot { |
| public: |
| typedef typename |
| detail::IF< |
| // is_protectable<Act>::value && is_lambda_functor<A>::value, |
| ice_and<is_protectable<Act>::value, is_lambda_functor<A>::value>::value, |
| lambda_functor< |
| lambda_functor_base< |
| Act, |
| tuple<typename detail::remove_reference_and_cv<A>::type> |
| > |
| >, |
| typename return_type_1<Act, A>::type |
| >::RET type; |
| }; |
| |
| // take care of the unavoidable instantiation for nullary case |
| template<class Act> struct return_type_1_prot<Act, null_type> { |
| typedef null_type type; |
| }; |
| |
| // Unary actions (result from unary operators) |
| // do not have a default return type. |
| template<class Act, class A> struct return_type_1 { |
| typedef typename |
| detail::return_type_deduction_failure<return_type_1> type; |
| }; |
| |
| |
| namespace detail { |
| |
| template <class T> |
| class protect_conversion { |
| typedef typename ndnboost::remove_reference<T>::type non_ref_T; |
| public: |
| |
| // add const to rvalues, so that all rvalues are stored as const in |
| // the args tuple |
| typedef typename detail::IF_type< |
| // ndnboost::is_reference<T>::value && !ndnboost::is_const<non_ref_T>::value, |
| ice_and<ndnboost::is_reference<T>::value, |
| ice_not<ndnboost::is_const<non_ref_T>::value>::value>::value, |
| detail::identity_mapping<T>, |
| const_copy_argument<non_ref_T> // handles funtion and array |
| >::type type; // types correctly |
| }; |
| |
| } // end detail |
| |
| template <class Act, class A, class B> struct return_type_2_prot { |
| |
| // experimental feature |
| // We may have a lambda functor as a result type of a subexpression |
| // (if protect) has been used. |
| // Thus, if one of the parameter types is a lambda functor, the result |
| // is a lambda functor as well. |
| // We need to make a conservative choise here. |
| // The resulting lambda functor stores all const reference arguments as |
| // const copies. References to non-const are stored as such. |
| // So if the source of the argument is a const open argument, a bound |
| // argument stored as a const reference, or a function returning a |
| // const reference, that information is lost. There is no way of |
| // telling apart 'real const references' from just 'LL internal |
| // const references' (or it would be really hard) |
| |
| // The return type is a subclass of lambda_functor, which has a converting |
| // copy constructor. It can copy any lambda functor, that has the same |
| // action type and code, and a copy compatible argument tuple. |
| |
| |
| typedef typename ndnboost::remove_reference<A>::type non_ref_A; |
| typedef typename ndnboost::remove_reference<B>::type non_ref_B; |
| |
| typedef typename |
| detail::IF< |
| // is_protectable<Act>::value && |
| // (is_lambda_functor<A>::value || is_lambda_functor<B>::value), |
| ice_and<is_protectable<Act>::value, |
| ice_or<is_lambda_functor<A>::value, |
| is_lambda_functor<B>::value>::value>::value, |
| lambda_functor< |
| lambda_functor_base< |
| Act, |
| tuple<typename detail::protect_conversion<A>::type, |
| typename detail::protect_conversion<B>::type> |
| > |
| >, |
| typename return_type_2<Act, non_ref_A, non_ref_B>::type |
| >::RET type; |
| }; |
| |
| // take care of the unavoidable instantiation for nullary case |
| template<class Act> struct return_type_2_prot<Act, null_type, null_type> { |
| typedef null_type type; |
| }; |
| // take care of the unavoidable instantiation for nullary case |
| template<class Act, class Other> struct return_type_2_prot<Act, Other, null_type> { |
| typedef null_type type; |
| }; |
| // take care of the unavoidable instantiation for nullary case |
| template<class Act, class Other> struct return_type_2_prot<Act, null_type, Other> { |
| typedef null_type type; |
| }; |
| |
| // comma is a special case, as the user defined operator can return |
| // an lvalue (reference) too, hence it must be handled at this level. |
| template<class A, class B> |
| struct return_type_2_comma |
| { |
| typedef typename ndnboost::remove_reference<A>::type non_ref_A; |
| typedef typename ndnboost::remove_reference<B>::type non_ref_B; |
| |
| typedef typename |
| detail::IF< |
| // is_protectable<other_action<comma_action> >::value && // it is protectable |
| // (is_lambda_functor<A>::value || is_lambda_functor<B>::value), |
| ice_and<is_protectable<other_action<comma_action> >::value, // it is protectable |
| ice_or<is_lambda_functor<A>::value, |
| is_lambda_functor<B>::value>::value>::value, |
| lambda_functor< |
| lambda_functor_base< |
| other_action<comma_action>, |
| tuple<typename detail::protect_conversion<A>::type, |
| typename detail::protect_conversion<B>::type> |
| > |
| >, |
| typename |
| return_type_2<other_action<comma_action>, non_ref_A, non_ref_B>::type |
| >::RET type1; |
| |
| // if no user defined return_type_2 (or plain_return_type_2) specialization |
| // matches, then return the righthand argument |
| typedef typename |
| detail::IF< |
| ndnboost::is_same<type1, detail::unspecified>::value, |
| B, |
| type1 |
| >::RET type; |
| |
| }; |
| |
| |
| // currently there are no protectable actions with > 2 args |
| |
| template<class Act, class Args> struct return_type_N_prot { |
| typedef typename return_type_N<Act, Args>::type type; |
| }; |
| |
| // take care of the unavoidable instantiation for nullary case |
| template<class Act> struct return_type_N_prot<Act, null_type> { |
| typedef null_type type; |
| }; |
| |
| // handle different kind of actions ------------------------ |
| |
| // use the return type given in the bind invocation as bind<Ret>(...) |
| template<int I, class Args, class Ret> |
| struct return_type_N<function_action<I, Ret>, Args> { |
| typedef Ret type; |
| }; |
| |
| // ::result_type support |
| |
| namespace detail |
| { |
| |
| BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type) |
| |
| template<class F> struct get_result_type |
| { |
| typedef typename F::result_type type; |
| }; |
| |
| template<class F, class A> struct get_sig |
| { |
| typedef typename function_adaptor<F>::template sig<A>::type type; |
| }; |
| |
| } // namespace detail |
| |
| // Ret is detail::unspecified, so try to deduce return type |
| template<int I, class Args> |
| struct return_type_N<function_action<I, detail::unspecified>, Args > { |
| |
| // in the case of function action, the first element in Args is |
| // some type of function |
| typedef typename Args::head_type Func; |
| typedef typename detail::remove_reference_and_cv<Func>::type plain_Func; |
| |
| public: |
| // pass the function to function_adaptor, and get the return type from |
| // that |
| typedef typename detail::IF< |
| detail::has_result_type<plain_Func>::value, |
| detail::get_result_type<plain_Func>, |
| detail::get_sig<plain_Func, Args> |
| >::RET::type type; |
| }; |
| |
| |
| } // namespace lambda |
| } // namespace ndnboost |
| |
| #endif |
| |
| |
| |