270 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			270 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | //  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 "boost/mpl/has_xxx.hpp" | ||
|  | 
 | ||
|  | #include <cstddef> // needed for the ptrdiff_t | ||
|  | 
 | ||
|  | namespace boost {  | ||
|  | namespace lambda { | ||
|  | 
 | ||
|  | // 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, | ||
|  |       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 boost::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< | ||
|  |       boost::is_reference<T>::value && !boost::is_const<non_ref_T>::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 boost::remove_reference<A>::type non_ref_A; | ||
|  |   typedef typename boost::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), | ||
|  |     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 boost::remove_reference<A>::type non_ref_A; | ||
|  |   typedef typename boost::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), | ||
|  |     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< | ||
|  |       boost::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 boost | ||
|  | 
 | ||
|  | #endif | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 |