if.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. // Boost Lambda Library -- if.hpp ------------------------------------------
  2. // Copyright (C) 1999, 2000 Jaakko Jarvi ([email protected])
  3. // Copyright (C) 2000 Gary Powell ([email protected])
  4. // Copyright (C) 2001-2002 Joel de Guzman
  5. //
  6. // Distributed under the Boost Software License, Version 1.0. (See
  7. // accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. // For more information, see www.boost.org
  11. // --------------------------------------------------------------------------
  12. #if !defined(BOOST_LAMBDA_IF_HPP)
  13. #define BOOST_LAMBDA_IF_HPP
  14. #include "boost/lambda/core.hpp"
  15. // Arithmetic type promotion needed for if_then_else_return
  16. #include "boost/lambda/detail/operator_actions.hpp"
  17. #include "boost/lambda/detail/operator_return_type_traits.hpp"
  18. namespace boost {
  19. namespace lambda {
  20. // -- if control construct actions ----------------------
  21. class ifthen_action {};
  22. class ifthenelse_action {};
  23. class ifthenelsereturn_action {};
  24. // Specialization for if_then.
  25. template<class Args>
  26. class
  27. lambda_functor_base<ifthen_action, Args> {
  28. public:
  29. Args args;
  30. template <class T> struct sig { typedef void type; };
  31. public:
  32. explicit lambda_functor_base(const Args& a) : args(a) {}
  33. template<class RET, CALL_TEMPLATE_ARGS>
  34. RET call(CALL_FORMAL_ARGS) const {
  35. if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
  36. detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
  37. }
  38. };
  39. // If Then
  40. template <class Arg1, class Arg2>
  41. inline const
  42. lambda_functor<
  43. lambda_functor_base<
  44. ifthen_action,
  45. tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
  46. >
  47. >
  48. if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
  49. return
  50. lambda_functor_base<
  51. ifthen_action,
  52. tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
  53. >
  54. ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
  55. }
  56. // Specialization for if_then_else.
  57. template<class Args>
  58. class
  59. lambda_functor_base<ifthenelse_action, Args> {
  60. public:
  61. Args args;
  62. template <class T> struct sig { typedef void type; };
  63. public:
  64. explicit lambda_functor_base(const Args& a) : args(a) {}
  65. template<class RET, CALL_TEMPLATE_ARGS>
  66. RET call(CALL_FORMAL_ARGS) const {
  67. if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
  68. detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
  69. else
  70. detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
  71. }
  72. };
  73. // If then else
  74. template <class Arg1, class Arg2, class Arg3>
  75. inline const
  76. lambda_functor<
  77. lambda_functor_base<
  78. ifthenelse_action,
  79. tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
  80. >
  81. >
  82. if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
  83. const lambda_functor<Arg3>& a3) {
  84. return
  85. lambda_functor_base<
  86. ifthenelse_action,
  87. tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
  88. >
  89. (tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
  90. (a1, a2, a3) );
  91. }
  92. // Our version of operator?:()
  93. template <class Arg1, class Arg2, class Arg3>
  94. inline const
  95. lambda_functor<
  96. lambda_functor_base<
  97. other_action<ifthenelsereturn_action>,
  98. tuple<lambda_functor<Arg1>,
  99. typename const_copy_argument<Arg2>::type,
  100. typename const_copy_argument<Arg3>::type>
  101. >
  102. >
  103. if_then_else_return(const lambda_functor<Arg1>& a1,
  104. const Arg2 & a2,
  105. const Arg3 & a3) {
  106. return
  107. lambda_functor_base<
  108. other_action<ifthenelsereturn_action>,
  109. tuple<lambda_functor<Arg1>,
  110. typename const_copy_argument<Arg2>::type,
  111. typename const_copy_argument<Arg3>::type>
  112. > ( tuple<lambda_functor<Arg1>,
  113. typename const_copy_argument<Arg2>::type,
  114. typename const_copy_argument<Arg3>::type> (a1, a2, a3) );
  115. }
  116. namespace detail {
  117. // return type specialization for conditional expression begins -----------
  118. // start reading below and move upwards
  119. // PHASE 6:1
  120. // check if A is conbertible to B and B to A
  121. template<int Phase, bool AtoB, bool BtoA, bool SameType, class A, class B>
  122. struct return_type_2_ifthenelsereturn;
  123. // if A can be converted to B and vice versa -> ambiguous
  124. template<int Phase, class A, class B>
  125. struct return_type_2_ifthenelsereturn<Phase, true, true, false, A, B> {
  126. typedef
  127. detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
  128. // ambiguous type in conditional expression
  129. };
  130. // if A can be converted to B and vice versa and are of same type
  131. template<int Phase, class A, class B>
  132. struct return_type_2_ifthenelsereturn<Phase, true, true, true, A, B> {
  133. typedef A type;
  134. };
  135. // A can be converted to B
  136. template<int Phase, class A, class B>
  137. struct return_type_2_ifthenelsereturn<Phase, true, false, false, A, B> {
  138. typedef B type;
  139. };
  140. // B can be converted to A
  141. template<int Phase, class A, class B>
  142. struct return_type_2_ifthenelsereturn<Phase, false, true, false, A, B> {
  143. typedef A type;
  144. };
  145. // neither can be converted. Then we drop the potential references, and
  146. // try again
  147. template<class A, class B>
  148. struct return_type_2_ifthenelsereturn<1, false, false, false, A, B> {
  149. // it is safe to add const, since the result will be an rvalue and thus
  150. // const anyway. The const are needed eg. if the types
  151. // are 'const int*' and 'void *'. The remaining type should be 'const void*'
  152. typedef const typename boost::remove_reference<A>::type plainA;
  153. typedef const typename boost::remove_reference<B>::type plainB;
  154. // TODO: Add support for volatile ?
  155. typedef typename
  156. return_type_2_ifthenelsereturn<
  157. 2,
  158. boost::is_convertible<plainA,plainB>::value,
  159. boost::is_convertible<plainB,plainA>::value,
  160. boost::is_same<plainA,plainB>::value,
  161. plainA,
  162. plainB>::type type;
  163. };
  164. // PHASE 6:2
  165. template<class A, class B>
  166. struct return_type_2_ifthenelsereturn<2, false, false, false, A, B> {
  167. typedef
  168. detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
  169. // types_do_not_match_in_conditional_expression
  170. };
  171. // PHASE 5: now we know that types are not arithmetic.
  172. template<class A, class B>
  173. struct non_numeric_types {
  174. typedef typename
  175. return_type_2_ifthenelsereturn<
  176. 1, // phase 1
  177. is_convertible<A,B>::value,
  178. is_convertible<B,A>::value,
  179. is_same<A,B>::value,
  180. A,
  181. B>::type type;
  182. };
  183. // PHASE 4 :
  184. // the base case covers arithmetic types with differing promote codes
  185. // use the type deduction of arithmetic_actions
  186. template<int CodeA, int CodeB, class A, class B>
  187. struct arithmetic_or_not {
  188. typedef typename
  189. return_type_2<arithmetic_action<plus_action>, A, B>::type type;
  190. // plus_action is just a random pick, has to be a concrete instance
  191. };
  192. // this case covers the case of artihmetic types with the same promote codes.
  193. // non numeric deduction is used since e.g. integral promotion is not
  194. // performed with operator ?:
  195. template<int CodeA, class A, class B>
  196. struct arithmetic_or_not<CodeA, CodeA, A, B> {
  197. typedef typename non_numeric_types<A, B>::type type;
  198. };
  199. // if either A or B has promote code -1 it is not an arithmetic type
  200. template<class A, class B>
  201. struct arithmetic_or_not <-1, -1, A, B> {
  202. typedef typename non_numeric_types<A, B>::type type;
  203. };
  204. template<int CodeB, class A, class B>
  205. struct arithmetic_or_not <-1, CodeB, A, B> {
  206. typedef typename non_numeric_types<A, B>::type type;
  207. };
  208. template<int CodeA, class A, class B>
  209. struct arithmetic_or_not <CodeA, -1, A, B> {
  210. typedef typename non_numeric_types<A, B>::type type;
  211. };
  212. // PHASE 3 : Are the types same?
  213. // No, check if they are arithmetic or not
  214. template <class A, class B>
  215. struct same_or_not {
  216. typedef typename detail::remove_reference_and_cv<A>::type plainA;
  217. typedef typename detail::remove_reference_and_cv<B>::type plainB;
  218. typedef typename
  219. arithmetic_or_not<
  220. detail::promote_code<plainA>::value,
  221. detail::promote_code<plainB>::value,
  222. A,
  223. B>::type type;
  224. };
  225. // Yes, clear.
  226. template <class A> struct same_or_not<A, A> {
  227. typedef A type;
  228. };
  229. } // detail
  230. // PHASE 2 : Perform first the potential array_to_pointer conversion
  231. template<class A, class B>
  232. struct return_type_2<other_action<ifthenelsereturn_action>, A, B> {
  233. typedef typename detail::array_to_pointer<A>::type A1;
  234. typedef typename detail::array_to_pointer<B>::type B1;
  235. typedef typename
  236. boost::add_const<typename detail::same_or_not<A1, B1>::type>::type type;
  237. };
  238. // PHASE 1 : Deduction is based on the second and third operand
  239. // return type specialization for conditional expression ends -----------
  240. // Specialization of lambda_functor_base for if_then_else_return.
  241. template<class Args>
  242. class
  243. lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
  244. public:
  245. Args args;
  246. template <class SigArgs> struct sig {
  247. private:
  248. typedef typename detail::nth_return_type_sig<1, Args, SigArgs>::type ret1;
  249. typedef typename detail::nth_return_type_sig<2, Args, SigArgs>::type ret2;
  250. public:
  251. typedef typename return_type_2<
  252. other_action<ifthenelsereturn_action>, ret1, ret2
  253. >::type type;
  254. };
  255. public:
  256. explicit lambda_functor_base(const Args& a) : args(a) {}
  257. template<class RET, CALL_TEMPLATE_ARGS>
  258. RET call(CALL_FORMAL_ARGS) const {
  259. return (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) ?
  260. detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS)
  261. :
  262. detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
  263. }
  264. };
  265. // The code below is from Joel de Guzman, some name changes etc.
  266. // has been made.
  267. ///////////////////////////////////////////////////////////////////////////////
  268. //
  269. // if_then_else_composite
  270. //
  271. // This composite has two (2) forms:
  272. //
  273. // if_(condition)
  274. // [
  275. // statement
  276. // ]
  277. //
  278. // and
  279. //
  280. // if_(condition)
  281. // [
  282. // true_statement
  283. // ]
  284. // .else_
  285. // [
  286. // false_statement
  287. // ]
  288. //
  289. // where condition is an lambda_functor that evaluates to bool. If condition
  290. // is true, the true_statement (again an lambda_functor) is executed
  291. // otherwise, the false_statement (another lambda_functor) is executed. The
  292. // result type of this is void. Note the trailing underscore after
  293. // if_ and the leading dot and the trailing underscore before
  294. // and after .else_.
  295. //
  296. ///////////////////////////////////////////////////////////////////////////////
  297. template <typename CondT, typename ThenT, typename ElseT>
  298. struct if_then_else_composite {
  299. typedef if_then_else_composite<CondT, ThenT, ElseT> self_t;
  300. template <class SigArgs>
  301. struct sig { typedef void type; };
  302. if_then_else_composite(
  303. CondT const& cond_,
  304. ThenT const& then_,
  305. ElseT const& else__)
  306. : cond(cond_), then(then_), else_(else__) {}
  307. template <class Ret, CALL_TEMPLATE_ARGS>
  308. Ret call(CALL_FORMAL_ARGS) const
  309. {
  310. if (cond.internal_call(CALL_ACTUAL_ARGS))
  311. then.internal_call(CALL_ACTUAL_ARGS);
  312. else
  313. else_.internal_call(CALL_ACTUAL_ARGS);
  314. }
  315. CondT cond; ThenT then; ElseT else_; // lambda_functors
  316. };
  317. //////////////////////////////////
  318. template <typename CondT, typename ThenT>
  319. struct else_gen {
  320. else_gen(CondT const& cond_, ThenT const& then_)
  321. : cond(cond_), then(then_) {}
  322. template <typename ElseT>
  323. lambda_functor<if_then_else_composite<CondT, ThenT,
  324. typename as_lambda_functor<ElseT>::type> >
  325. operator[](ElseT const& else_)
  326. {
  327. typedef if_then_else_composite<CondT, ThenT,
  328. typename as_lambda_functor<ElseT>::type>
  329. result;
  330. return result(cond, then, to_lambda_functor(else_));
  331. }
  332. CondT cond; ThenT then;
  333. };
  334. //////////////////////////////////
  335. template <typename CondT, typename ThenT>
  336. struct if_then_composite {
  337. template <class SigArgs>
  338. struct sig { typedef void type; };
  339. if_then_composite(CondT const& cond_, ThenT const& then_)
  340. : cond(cond_), then(then_), else_(cond, then) {}
  341. template <class Ret, CALL_TEMPLATE_ARGS>
  342. Ret call(CALL_FORMAL_ARGS) const
  343. {
  344. if (cond.internal_call(CALL_ACTUAL_ARGS))
  345. then.internal_call(CALL_ACTUAL_ARGS);
  346. }
  347. CondT cond; ThenT then; // lambda_functors
  348. else_gen<CondT, ThenT> else_;
  349. };
  350. //////////////////////////////////
  351. template <typename CondT>
  352. struct if_gen {
  353. if_gen(CondT const& cond_)
  354. : cond(cond_) {}
  355. template <typename ThenT>
  356. lambda_functor<if_then_composite<
  357. typename as_lambda_functor<CondT>::type,
  358. typename as_lambda_functor<ThenT>::type> >
  359. operator[](ThenT const& then) const
  360. {
  361. typedef if_then_composite<
  362. typename as_lambda_functor<CondT>::type,
  363. typename as_lambda_functor<ThenT>::type>
  364. result;
  365. return result(
  366. to_lambda_functor(cond),
  367. to_lambda_functor(then));
  368. }
  369. CondT cond;
  370. };
  371. //////////////////////////////////
  372. template <typename CondT>
  373. inline if_gen<CondT>
  374. if_(CondT const& cond)
  375. {
  376. return if_gen<CondT>(cond);
  377. }
  378. } // lambda
  379. } // boost
  380. #endif // BOOST_LAMBDA_IF_HPP