return_type_traits.hpp 8.6 KB

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