Update contrib.
1 // Boost Lambda Library -- if.hpp ------------------------------------------
3 // Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
4 // Copyright (C) 2000 Gary Powell (powellg@amazon.com)
5 // Copyright (C) 2001-2002 Joel de Guzman
7 // Distributed under the Boost Software License, Version 1.0. (See
8 // accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
11 // For more information, see www.boost.org
13 // --------------------------------------------------------------------------
15 #if !defined(BOOST_LAMBDA_IF_HPP)
16 #define BOOST_LAMBDA_IF_HPP
18 #include "boost/lambda/core.hpp"
20 // Arithmetic type promotion needed for if_then_else_return
21 #include "boost/lambda/detail/operator_actions.hpp"
22 #include "boost/lambda/detail/operator_return_type_traits.hpp"
27 // -- if control construct actions ----------------------
29 class ifthen_action {};
30 class ifthenelse_action {};
31 class ifthenelsereturn_action {};
33 // Specialization for if_then.
36 lambda_functor_base<ifthen_action, Args> {
39 template <class T> struct sig { typedef void type; };
41 explicit lambda_functor_base(const Args& a) : args(a) {}
43 template<class RET, CALL_TEMPLATE_ARGS>
44 RET call(CALL_FORMAL_ARGS) const {
45 if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
46 detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
51 template <class Arg1, class Arg2>
56 tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
59 if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
63 tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
65 ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
69 // Specialization for if_then_else.
72 lambda_functor_base<ifthenelse_action, Args> {
75 template <class T> struct sig { typedef void type; };
77 explicit lambda_functor_base(const Args& a) : args(a) {}
79 template<class RET, CALL_TEMPLATE_ARGS>
80 RET call(CALL_FORMAL_ARGS) const {
81 if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
82 detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
84 detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
92 template <class Arg1, class Arg2, class Arg3>
97 tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
100 if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
101 const lambda_functor<Arg3>& a3) {
105 tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
107 (tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
111 // Our version of operator?:()
113 template <class Arg1, class Arg2, class Arg3>
117 other_action<ifthenelsereturn_action>,
118 tuple<lambda_functor<Arg1>,
119 typename const_copy_argument<Arg2>::type,
120 typename const_copy_argument<Arg3>::type>
123 if_then_else_return(const lambda_functor<Arg1>& a1,
128 other_action<ifthenelsereturn_action>,
129 tuple<lambda_functor<Arg1>,
130 typename const_copy_argument<Arg2>::type,
131 typename const_copy_argument<Arg3>::type>
132 > ( tuple<lambda_functor<Arg1>,
133 typename const_copy_argument<Arg2>::type,
134 typename const_copy_argument<Arg3>::type> (a1, a2, a3) );
139 // return type specialization for conditional expression begins -----------
140 // start reading below and move upwards
143 // check if A is conbertible to B and B to A
144 template<int Phase, bool AtoB, bool BtoA, bool SameType, class A, class B>
145 struct return_type_2_ifthenelsereturn;
147 // if A can be converted to B and vice versa -> ambiguous
148 template<int Phase, class A, class B>
149 struct return_type_2_ifthenelsereturn<Phase, true, true, false, A, B> {
151 detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
152 // ambiguous type in conditional expression
154 // if A can be converted to B and vice versa and are of same type
155 template<int Phase, class A, class B>
156 struct return_type_2_ifthenelsereturn<Phase, true, true, true, A, B> {
161 // A can be converted to B
162 template<int Phase, class A, class B>
163 struct return_type_2_ifthenelsereturn<Phase, true, false, false, A, B> {
167 // B can be converted to A
168 template<int Phase, class A, class B>
169 struct return_type_2_ifthenelsereturn<Phase, false, true, false, A, B> {
173 // neither can be converted. Then we drop the potential references, and
175 template<class A, class B>
176 struct return_type_2_ifthenelsereturn<1, false, false, false, A, B> {
177 // it is safe to add const, since the result will be an rvalue and thus
178 // const anyway. The const are needed eg. if the types
179 // are 'const int*' and 'void *'. The remaining type should be 'const void*'
180 typedef const typename boost::remove_reference<A>::type plainA;
181 typedef const typename boost::remove_reference<B>::type plainB;
182 // TODO: Add support for volatile ?
185 return_type_2_ifthenelsereturn<
187 boost::is_convertible<plainA,plainB>::value,
188 boost::is_convertible<plainB,plainA>::value,
189 boost::is_same<plainA,plainB>::value,
195 template<class A, class B>
196 struct return_type_2_ifthenelsereturn<2, false, false, false, A, B> {
198 detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
199 // types_do_not_match_in_conditional_expression
204 // PHASE 5: now we know that types are not arithmetic.
205 template<class A, class B>
206 struct non_numeric_types {
208 return_type_2_ifthenelsereturn<
210 is_convertible<A,B>::value,
211 is_convertible<B,A>::value,
218 // the base case covers arithmetic types with differing promote codes
219 // use the type deduction of arithmetic_actions
220 template<int CodeA, int CodeB, class A, class B>
221 struct arithmetic_or_not {
223 return_type_2<arithmetic_action<plus_action>, A, B>::type type;
224 // plus_action is just a random pick, has to be a concrete instance
227 // this case covers the case of artihmetic types with the same promote codes.
228 // non numeric deduction is used since e.g. integral promotion is not
229 // performed with operator ?:
230 template<int CodeA, class A, class B>
231 struct arithmetic_or_not<CodeA, CodeA, A, B> {
232 typedef typename non_numeric_types<A, B>::type type;
235 // if either A or B has promote code -1 it is not an arithmetic type
236 template<class A, class B>
237 struct arithmetic_or_not <-1, -1, A, B> {
238 typedef typename non_numeric_types<A, B>::type type;
240 template<int CodeB, class A, class B>
241 struct arithmetic_or_not <-1, CodeB, A, B> {
242 typedef typename non_numeric_types<A, B>::type type;
244 template<int CodeA, class A, class B>
245 struct arithmetic_or_not <CodeA, -1, A, B> {
246 typedef typename non_numeric_types<A, B>::type type;
252 // PHASE 3 : Are the types same?
253 // No, check if they are arithmetic or not
254 template <class A, class B>
256 typedef typename detail::remove_reference_and_cv<A>::type plainA;
257 typedef typename detail::remove_reference_and_cv<B>::type plainB;
261 detail::promote_code<plainA>::value,
262 detail::promote_code<plainB>::value,
267 template <class A> struct same_or_not<A, A> {
273 // PHASE 2 : Perform first the potential array_to_pointer conversion
274 template<class A, class B>
275 struct return_type_2<other_action<ifthenelsereturn_action>, A, B> {
277 typedef typename detail::array_to_pointer<A>::type A1;
278 typedef typename detail::array_to_pointer<B>::type B1;
281 boost::add_const<typename detail::same_or_not<A1, B1>::type>::type type;
284 // PHASE 1 : Deduction is based on the second and third operand
287 // return type specialization for conditional expression ends -----------
290 // Specialization of lambda_functor_base for if_then_else_return.
293 lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
297 template <class SigArgs> struct sig {
299 typedef typename detail::nth_return_type_sig<1, Args, SigArgs>::type ret1;
300 typedef typename detail::nth_return_type_sig<2, Args, SigArgs>::type ret2;
302 typedef typename return_type_2<
303 other_action<ifthenelsereturn_action>, ret1, ret2
308 explicit lambda_functor_base(const Args& a) : args(a) {}
310 template<class RET, CALL_TEMPLATE_ARGS>
311 RET call(CALL_FORMAL_ARGS) const {
312 return (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) ?
313 detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS)
315 detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
319 // The code below is from Joel de Guzman, some name changes etc.
322 ///////////////////////////////////////////////////////////////////////////////
324 // if_then_else_composite
326 // This composite has two (2) forms:
344 // where condition is an lambda_functor that evaluates to bool. If condition
345 // is true, the true_statement (again an lambda_functor) is executed
346 // otherwise, the false_statement (another lambda_functor) is executed. The
347 // result type of this is void. Note the trailing underscore after
348 // if_ and the the leading dot and the trailing underscore before
351 ///////////////////////////////////////////////////////////////////////////////
352 template <typename CondT, typename ThenT, typename ElseT>
353 struct if_then_else_composite {
355 typedef if_then_else_composite<CondT, ThenT, ElseT> self_t;
357 template <class SigArgs>
358 struct sig { typedef void type; };
360 if_then_else_composite(
364 : cond(cond_), then(then_), else_(else__) {}
366 template <class Ret, CALL_TEMPLATE_ARGS>
367 Ret call(CALL_FORMAL_ARGS) const
369 if (cond.internal_call(CALL_ACTUAL_ARGS))
370 then.internal_call(CALL_ACTUAL_ARGS);
372 else_.internal_call(CALL_ACTUAL_ARGS);
375 CondT cond; ThenT then; ElseT else_; // lambda_functors
378 //////////////////////////////////
379 template <typename CondT, typename ThenT>
382 else_gen(CondT const& cond_, ThenT const& then_)
383 : cond(cond_), then(then_) {}
385 template <typename ElseT>
386 lambda_functor<if_then_else_composite<CondT, ThenT,
387 typename as_lambda_functor<ElseT>::type> >
388 operator[](ElseT const& else_)
390 typedef if_then_else_composite<CondT, ThenT,
391 typename as_lambda_functor<ElseT>::type>
394 return result(cond, then, to_lambda_functor(else_));
397 CondT cond; ThenT then;
400 //////////////////////////////////
401 template <typename CondT, typename ThenT>
402 struct if_then_composite {
404 template <class SigArgs>
405 struct sig { typedef void type; };
407 if_then_composite(CondT const& cond_, ThenT const& then_)
408 : cond(cond_), then(then_), else_(cond, then) {}
410 template <class Ret, CALL_TEMPLATE_ARGS>
411 Ret call(CALL_FORMAL_ARGS) const
413 if (cond.internal_call(CALL_ACTUAL_ARGS))
414 then.internal_call(CALL_ACTUAL_ARGS);
417 CondT cond; ThenT then; // lambda_functors
418 else_gen<CondT, ThenT> else_;
421 //////////////////////////////////
422 template <typename CondT>
425 if_gen(CondT const& cond_)
428 template <typename ThenT>
429 lambda_functor<if_then_composite<
430 typename as_lambda_functor<CondT>::type,
431 typename as_lambda_functor<ThenT>::type> >
432 operator[](ThenT const& then) const
434 typedef if_then_composite<
435 typename as_lambda_functor<CondT>::type,
436 typename as_lambda_functor<ThenT>::type>
440 to_lambda_functor(cond),
441 to_lambda_functor(then));
447 //////////////////////////////////
448 template <typename CondT>
450 if_(CondT const& cond)
452 return if_gen<CondT>(cond);
460 #endif // BOOST_LAMBDA_IF_HPP