1 // Boost Lambda Library -- if.hpp ------------------------------------------
3 // Copyright (C) 1999, 2000 Jaakko Jarvi (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