fix doc example typo
[boost.git] / boost / lambda / if.hpp
blob9ee915c0efe223d9ceb49920b7033188f11283b7
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
6 //
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"
24 namespace boost {
25 namespace lambda {
27 // -- if control construct actions ----------------------
29 class ifthen_action {};
30 class ifthenelse_action {};
31 class ifthenelsereturn_action {};
33 // Specialization for if_then.
34 template<class Args>
35 class
36 lambda_functor_base<ifthen_action, Args> {
37 public:
38 Args args;
39 template <class T> struct sig { typedef void type; };
40 public:
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);
50 // If Then
51 template <class Arg1, class Arg2>
52 inline const
53 lambda_functor<
54 lambda_functor_base<
55 ifthen_action,
56 tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
59 if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
60 return
61 lambda_functor_base<
62 ifthen_action,
63 tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
65 ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
69 // Specialization for if_then_else.
70 template<class Args>
71 class
72 lambda_functor_base<ifthenelse_action, Args> {
73 public:
74 Args args;
75 template <class T> struct sig { typedef void type; };
76 public:
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);
83 else
84 detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
90 // If then else
92 template <class Arg1, class Arg2, class Arg3>
93 inline const
94 lambda_functor<
95 lambda_functor_base<
96 ifthenelse_action,
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) {
102 return
103 lambda_functor_base<
104 ifthenelse_action,
105 tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
107 (tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
108 (a1, a2, a3) );
111 // Our version of operator?:()
113 template <class Arg1, class Arg2, class Arg3>
114 inline const
115 lambda_functor<
116 lambda_functor_base<
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,
124 const Arg2 & a2,
125 const Arg3 & a3) {
126 return
127 lambda_functor_base<
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) );
137 namespace detail {
139 // return type specialization for conditional expression begins -----------
140 // start reading below and move upwards
142 // PHASE 6:1
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> {
150 typedef
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> {
157 typedef A type;
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> {
164 typedef B type;
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> {
170 typedef A type;
173 // neither can be converted. Then we drop the potential references, and
174 // try again
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 ?
184 typedef typename
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,
190 plainA,
191 plainB>::type type;
194 // PHASE 6:2
195 template<class A, class B>
196 struct return_type_2_ifthenelsereturn<2, false, false, false, A, B> {
197 typedef
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 {
207 typedef typename
208 return_type_2_ifthenelsereturn<
209 1, // phase 1
210 is_convertible<A,B>::value,
211 is_convertible<B,A>::value,
212 is_same<A,B>::value,
214 B>::type type;
217 // PHASE 4 :
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 {
222 typedef typename
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>
255 struct same_or_not {
256 typedef typename detail::remove_reference_and_cv<A>::type plainA;
257 typedef typename detail::remove_reference_and_cv<B>::type plainB;
259 typedef typename
260 arithmetic_or_not<
261 detail::promote_code<plainA>::value,
262 detail::promote_code<plainB>::value,
264 B>::type type;
266 // Yes, clear.
267 template <class A> struct same_or_not<A, A> {
268 typedef A type;
271 } // detail
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;
280 typedef typename
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.
291 template<class Args>
292 class
293 lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
294 public:
295 Args args;
297 template <class SigArgs> struct sig {
298 private:
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;
301 public:
302 typedef typename return_type_2<
303 other_action<ifthenelsereturn_action>, ret1, ret2
304 >::type type;
307 public:
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.
320 // has been made.
322 ///////////////////////////////////////////////////////////////////////////////
324 // if_then_else_composite
326 // This composite has two (2) forms:
328 // if_(condition)
329 // [
330 // statement
331 // ]
333 // and
335 // if_(condition)
336 // [
337 // true_statement
338 // ]
339 // .else_
340 // [
341 // false_statement
342 // ]
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
349 // and after .else_.
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(
361 CondT const& cond_,
362 ThenT const& then_,
363 ElseT const& else__)
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);
371 else
372 else_.internal_call(CALL_ACTUAL_ARGS);
375 CondT cond; ThenT then; ElseT else_; // lambda_functors
378 //////////////////////////////////
379 template <typename CondT, typename ThenT>
380 struct else_gen {
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>
392 result;
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>
423 struct if_gen {
425 if_gen(CondT const& cond_)
426 : cond(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>
437 result;
439 return result(
440 to_lambda_functor(cond),
441 to_lambda_functor(then));
444 CondT cond;
447 //////////////////////////////////
448 template <typename CondT>
449 inline if_gen<CondT>
450 if_(CondT const& cond)
452 return if_gen<CondT>(cond);
457 } // lambda
458 } // boost
460 #endif // BOOST_LAMBDA_IF_HPP