// Boost Lambda Library -- if.hpp ------------------------------------------ // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) // Copyright (C) 2000 Gary Powell (powellg@amazon.com) // Copyright (C) 2001-2002 Joel de Guzman // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // For more information, see www.boost.org // -------------------------------------------------------------------------- #if !defined(BOOST_LAMBDA_IF_HPP) #define BOOST_LAMBDA_IF_HPP #include "boost/lambda/core.hpp" // Arithmetic type promotion needed for if_then_else_return #include "boost/lambda/detail/operator_actions.hpp" #include "boost/lambda/detail/operator_return_type_traits.hpp" namespace boost { namespace lambda { // -- if control construct actions ---------------------- class ifthen_action {}; class ifthenelse_action {}; class ifthenelsereturn_action {}; // Specialization for if_then. template class lambda_functor_base { public: Args args; template struct sig { typedef void type; }; public: explicit lambda_functor_base(const Args& a) : args(a) {} template RET call(CALL_FORMAL_ARGS) const { if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS); } }; // If Then template inline const lambda_functor< lambda_functor_base< ifthen_action, tuple, lambda_functor > > > if_then(const lambda_functor& a1, const lambda_functor& a2) { return lambda_functor_base< ifthen_action, tuple, lambda_functor > > ( tuple, lambda_functor >(a1, a2) ); } // Specialization for if_then_else. template class lambda_functor_base { public: Args args; template struct sig { typedef void type; }; public: explicit lambda_functor_base(const Args& a) : args(a) {} template RET call(CALL_FORMAL_ARGS) const { if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS); else detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS); } }; // If then else template inline const lambda_functor< lambda_functor_base< ifthenelse_action, tuple, lambda_functor, lambda_functor > > > if_then_else(const lambda_functor& a1, const lambda_functor& a2, const lambda_functor& a3) { return lambda_functor_base< ifthenelse_action, tuple, lambda_functor, lambda_functor > > (tuple, lambda_functor, lambda_functor > (a1, a2, a3) ); } // Our version of operator?:() template inline const lambda_functor< lambda_functor_base< other_action, tuple, typename const_copy_argument::type, typename const_copy_argument::type> > > if_then_else_return(const lambda_functor& a1, const Arg2 & a2, const Arg3 & a3) { return lambda_functor_base< other_action, tuple, typename const_copy_argument::type, typename const_copy_argument::type> > ( tuple, typename const_copy_argument::type, typename const_copy_argument::type> (a1, a2, a3) ); } namespace detail { // return type specialization for conditional expression begins ----------- // start reading below and move upwards // PHASE 6:1 // check if A is conbertible to B and B to A template struct return_type_2_ifthenelsereturn; // if A can be converted to B and vice versa -> ambiguous template struct return_type_2_ifthenelsereturn { typedef detail::return_type_deduction_failure type; // ambiguous type in conditional expression }; // if A can be converted to B and vice versa and are of same type template struct return_type_2_ifthenelsereturn { typedef A type; }; // A can be converted to B template struct return_type_2_ifthenelsereturn { typedef B type; }; // B can be converted to A template struct return_type_2_ifthenelsereturn { typedef A type; }; // neither can be converted. Then we drop the potential references, and // try again template struct return_type_2_ifthenelsereturn<1, false, false, false, A, B> { // it is safe to add const, since the result will be an rvalue and thus // const anyway. The const are needed eg. if the types // are 'const int*' and 'void *'. The remaining type should be 'const void*' typedef const typename boost::remove_reference::type plainA; typedef const typename boost::remove_reference::type plainB; // TODO: Add support for volatile ? typedef typename return_type_2_ifthenelsereturn< 2, boost::is_convertible::value, boost::is_convertible::value, boost::is_same::value, plainA, plainB>::type type; }; // PHASE 6:2 template struct return_type_2_ifthenelsereturn<2, false, false, false, A, B> { typedef detail::return_type_deduction_failure type; // types_do_not_match_in_conditional_expression }; // PHASE 5: now we know that types are not arithmetic. template struct non_numeric_types { typedef typename return_type_2_ifthenelsereturn< 1, // phase 1 is_convertible::value, is_convertible::value, is_same::value, A, B>::type type; }; // PHASE 4 : // the base case covers arithmetic types with differing promote codes // use the type deduction of arithmetic_actions template struct arithmetic_or_not { typedef typename return_type_2, A, B>::type type; // plus_action is just a random pick, has to be a concrete instance }; // this case covers the case of artihmetic types with the same promote codes. // non numeric deduction is used since e.g. integral promotion is not // performed with operator ?: template struct arithmetic_or_not { typedef typename non_numeric_types::type type; }; // if either A or B has promote code -1 it is not an arithmetic type template struct arithmetic_or_not <-1, -1, A, B> { typedef typename non_numeric_types::type type; }; template struct arithmetic_or_not <-1, CodeB, A, B> { typedef typename non_numeric_types::type type; }; template struct arithmetic_or_not { typedef typename non_numeric_types::type type; }; // PHASE 3 : Are the types same? // No, check if they are arithmetic or not template struct same_or_not { typedef typename detail::remove_reference_and_cv::type plainA; typedef typename detail::remove_reference_and_cv::type plainB; typedef typename arithmetic_or_not< detail::promote_code::value, detail::promote_code::value, A, B>::type type; }; // Yes, clear. template struct same_or_not { typedef A type; }; } // detail // PHASE 2 : Perform first the potential array_to_pointer conversion template struct return_type_2, A, B> { typedef typename detail::array_to_pointer::type A1; typedef typename detail::array_to_pointer::type B1; typedef typename boost::add_const::type>::type type; }; // PHASE 1 : Deduction is based on the second and third operand // return type specialization for conditional expression ends ----------- // Specialization of lambda_functor_base for if_then_else_return. template class lambda_functor_base, Args> { public: Args args; template struct sig { private: typedef typename detail::nth_return_type_sig<1, Args, SigArgs>::type ret1; typedef typename detail::nth_return_type_sig<2, Args, SigArgs>::type ret2; public: typedef typename return_type_2< other_action, ret1, ret2 >::type type; }; public: explicit lambda_functor_base(const Args& a) : args(a) {} template RET call(CALL_FORMAL_ARGS) const { return (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) ? detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS) : detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS); } }; // The code below is from Joel de Guzman, some name changes etc. // has been made. /////////////////////////////////////////////////////////////////////////////// // // if_then_else_composite // // This composite has two (2) forms: // // if_(condition) // [ // statement // ] // // and // // if_(condition) // [ // true_statement // ] // .else_ // [ // false_statement // ] // // where condition is an lambda_functor that evaluates to bool. If condition // is true, the true_statement (again an lambda_functor) is executed // otherwise, the false_statement (another lambda_functor) is executed. The // result type of this is void. Note the trailing underscore after // if_ and the the leading dot and the trailing underscore before // and after .else_. // /////////////////////////////////////////////////////////////////////////////// template struct if_then_else_composite { typedef if_then_else_composite self_t; template struct sig { typedef void type; }; if_then_else_composite( CondT const& cond_, ThenT const& then_, ElseT const& else__) : cond(cond_), then(then_), else_(else__) {} template Ret call(CALL_FORMAL_ARGS) const { if (cond.internal_call(CALL_ACTUAL_ARGS)) then.internal_call(CALL_ACTUAL_ARGS); else else_.internal_call(CALL_ACTUAL_ARGS); } CondT cond; ThenT then; ElseT else_; // lambda_functors }; ////////////////////////////////// template struct else_gen { else_gen(CondT const& cond_, ThenT const& then_) : cond(cond_), then(then_) {} template lambda_functor::type> > operator[](ElseT const& else_) { typedef if_then_else_composite::type> result; return result(cond, then, to_lambda_functor(else_)); } CondT cond; ThenT then; }; ////////////////////////////////// template struct if_then_composite { template struct sig { typedef void type; }; if_then_composite(CondT const& cond_, ThenT const& then_) : cond(cond_), then(then_), else_(cond, then) {} template Ret call(CALL_FORMAL_ARGS) const { if (cond.internal_call(CALL_ACTUAL_ARGS)) then.internal_call(CALL_ACTUAL_ARGS); } CondT cond; ThenT then; // lambda_functors else_gen else_; }; ////////////////////////////////// template struct if_gen { if_gen(CondT const& cond_) : cond(cond_) {} template lambda_functor::type, typename as_lambda_functor::type> > operator[](ThenT const& then) const { typedef if_then_composite< typename as_lambda_functor::type, typename as_lambda_functor::type> result; return result( to_lambda_functor(cond), to_lambda_functor(then)); } CondT cond; }; ////////////////////////////////// template inline if_gen if_(CondT const& cond) { return if_gen(cond); } } // lambda } // boost #endif // BOOST_LAMBDA_IF_HPP