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