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