1 // return_type_traits.hpp -- Boost Lambda Library --------------------------- 2 3 // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See 6 // accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 // 9 // For more information, see www.boost.org 10 11 12 #ifndef BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP 13 #define BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP 14 15 #include "boost/mpl/has_xxx.hpp" 16 17 #include <cstddef> // needed for the ptrdiff_t 18 19 namespace boost { 20 namespace lambda { 21 22 // Much of the type deduction code for standard arithmetic types 23 // from Gary Powell 24 25 // different arities: 26 template <class Act, class A1> struct return_type_1; // 1-ary actions 27 template <class Act, class A1, class A2> struct return_type_2; // 2-ary 28 template <class Act, class Args> struct return_type_N; // >3- ary 29 30 template <class Act, class A1> struct return_type_1_prot; 31 template <class Act, class A1, class A2> struct return_type_2_prot; // 2-ary 32 template <class Act, class A1> struct return_type_N_prot; // >3-ary 33 34 35 namespace detail { 36 37 template<class> class return_type_deduction_failure {}; 38 39 // In some cases return type deduction should fail (an invalid lambda 40 // expression). Sometimes the lambda expression can be ok, the return type 41 // just is not deducible (user defined operators). Then return type deduction 42 // should never be entered at all, and the use of ret<> does this. 43 // However, for nullary lambda functors, return type deduction is always 44 // entered, and there seems to be no way around this. 45 46 // (the return type is part of the prototype of the non-template 47 // operator()(). The prototype is instantiated, even though the body 48 // is not.) 49 50 // So, in the case the return type deduction should fail, it should not 51 // fail directly, but rather result in a valid but wrong return type, 52 // causing a compile time error only if the function is really called. 53 54 55 56 } // end detail 57 58 59 60 // return_type_X_prot classes -------------------------------------------- 61 // These classes are the first layer that gets instantiated from the 62 // lambda_functor_base sig templates. It will check whether 63 // the action is protectable and one of arguments is "protected" or its 64 // evaluation will otherwise result in another lambda functor. 65 // If this is a case, the result type will be another lambda functor. 66 67 // The arguments are always non-reference types, except for comma action 68 // where the right argument can be a reference too. This is because it 69 // matters (in the builtin case) whether the argument is an lvalue or 70 // rvalue: int i; i, 1 -> rvalue; 1, i -> lvalue 71 72 template <class Act, class A> struct return_type_1_prot { 73 public: 74 typedef typename 75 detail::IF< 76 is_protectable<Act>::value && is_lambda_functor<A>::value, 77 lambda_functor< 78 lambda_functor_base< 79 Act, 80 tuple<typename detail::remove_reference_and_cv<A>::type> 81 > 82 >, 83 typename return_type_1<Act, A>::type 84 >::RET type; 85 }; 86 87 // take care of the unavoidable instantiation for nullary case 88 template<class Act> struct return_type_1_prot<Act, null_type> { 89 typedef null_type type; 90 }; 91 92 // Unary actions (result from unary operators) 93 // do not have a default return type. 94 template<class Act, class A> struct return_type_1 { 95 typedef typename 96 detail::return_type_deduction_failure<return_type_1> type; 97 }; 98 99 100 namespace detail { 101 102 template <class T> 103 class protect_conversion { 104 typedef typename boost::remove_reference<T>::type non_ref_T; 105 public: 106 107 // add const to rvalues, so that all rvalues are stored as const in 108 // the args tuple 109 typedef typename detail::IF_type< 110 boost::is_reference<T>::value && !boost::is_const<non_ref_T>::value, 111 detail::identity_mapping<T>, 112 const_copy_argument<non_ref_T> // handles funtion and array 113 >::type type; // types correctly 114 }; 115 116 } // end detail 117 118 template <class Act, class A, class B> struct return_type_2_prot { 119 120 // experimental feature 121 // We may have a lambda functor as a result type of a subexpression 122 // (if protect) has been used. 123 // Thus, if one of the parameter types is a lambda functor, the result 124 // is a lambda functor as well. 125 // We need to make a conservative choise here. 126 // The resulting lambda functor stores all const reference arguments as 127 // const copies. References to non-const are stored as such. 128 // So if the source of the argument is a const open argument, a bound 129 // argument stored as a const reference, or a function returning a 130 // const reference, that information is lost. There is no way of 131 // telling apart 'real const references' from just 'LL internal 132 // const references' (or it would be really hard) 133 134 // The return type is a subclass of lambda_functor, which has a converting 135 // copy constructor. It can copy any lambda functor, that has the same 136 // action type and code, and a copy compatible argument tuple. 137 138 139 typedef typename boost::remove_reference<A>::type non_ref_A; 140 typedef typename boost::remove_reference<B>::type non_ref_B; 141 142 typedef typename 143 detail::IF< 144 is_protectable<Act>::value && 145 (is_lambda_functor<A>::value || is_lambda_functor<B>::value), 146 lambda_functor< 147 lambda_functor_base< 148 Act, 149 tuple<typename detail::protect_conversion<A>::type, 150 typename detail::protect_conversion<B>::type> 151 > 152 >, 153 typename return_type_2<Act, non_ref_A, non_ref_B>::type 154 >::RET type; 155 }; 156 157 // take care of the unavoidable instantiation for nullary case 158 template<class Act> struct return_type_2_prot<Act, null_type, null_type> { 159 typedef null_type type; 160 }; 161 // take care of the unavoidable instantiation for nullary case 162 template<class Act, class Other> struct return_type_2_prot<Act, Other, null_type> { 163 typedef null_type type; 164 }; 165 // take care of the unavoidable instantiation for nullary case 166 template<class Act, class Other> struct return_type_2_prot<Act, null_type, Other> { 167 typedef null_type type; 168 }; 169 170 // comma is a special case, as the user defined operator can return 171 // an lvalue (reference) too, hence it must be handled at this level. 172 template<class A, class B> 173 struct return_type_2_comma 174 { 175 typedef typename boost::remove_reference<A>::type non_ref_A; 176 typedef typename boost::remove_reference<B>::type non_ref_B; 177 178 typedef typename 179 detail::IF< 180 is_protectable<other_action<comma_action> >::value && // it is protectable 181 (is_lambda_functor<A>::value || is_lambda_functor<B>::value), 182 lambda_functor< 183 lambda_functor_base< 184 other_action<comma_action>, 185 tuple<typename detail::protect_conversion<A>::type, 186 typename detail::protect_conversion<B>::type> 187 > 188 >, 189 typename 190 return_type_2<other_action<comma_action>, non_ref_A, non_ref_B>::type 191 >::RET type1; 192 193 // if no user defined return_type_2 (or plain_return_type_2) specialization 194 // matches, then return the righthand argument 195 typedef typename 196 detail::IF< 197 boost::is_same<type1, detail::unspecified>::value, 198 B, 199 type1 200 >::RET type; 201 202 }; 203 204 205 // currently there are no protectable actions with > 2 args 206 207 template<class Act, class Args> struct return_type_N_prot { 208 typedef typename return_type_N<Act, Args>::type type; 209 }; 210 211 // take care of the unavoidable instantiation for nullary case 212 template<class Act> struct return_type_N_prot<Act, null_type> { 213 typedef null_type type; 214 }; 215 216 // handle different kind of actions ------------------------ 217 218 // use the return type given in the bind invocation as bind<Ret>(...) 219 template<int I, class Args, class Ret> 220 struct return_type_N<function_action<I, Ret>, Args> { 221 typedef Ret type; 222 }; 223 224 // ::result_type support 225 226 namespace detail 227 { 228 229 BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type) 230 231 template<class F> struct get_result_type 232 { 233 typedef typename F::result_type type; 234 }; 235 236 template<class F, class A> struct get_sig 237 { 238 typedef typename function_adaptor<F>::template sig<A>::type type; 239 }; 240 241 } // namespace detail 242 243 // Ret is detail::unspecified, so try to deduce return type 244 template<int I, class Args> 245 struct return_type_N<function_action<I, detail::unspecified>, Args > { 246 247 // in the case of function action, the first element in Args is 248 // some type of function 249 typedef typename Args::head_type Func; 250 typedef typename detail::remove_reference_and_cv<Func>::type plain_Func; 251 252 public: 253 // pass the function to function_adaptor, and get the return type from 254 // that 255 typedef typename detail::IF< 256 detail::has_result_type<plain_Func>::value, 257 detail::get_result_type<plain_Func>, 258 detail::get_sig<plain_Func, Args> 259 >::RET::type type; 260 }; 261 262 263 } // namespace lambda 264 } // namespace boost 265 266 #endif 267 268 269 270