// Boost Lambda Library -- if.hpp ------------------------------------------
// Copyright (C) 1999, 2000 Jaakko J鋜vi (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(args), CALL_ACTUAL_ARGS))
detail::select(boost::tuples::get(args), CALL_ACTUAL_ARGS);
}
};
// If Then
template
inline const
lambda_functor<
lambda_functor_base<
ifthen_action,
tuple
>
>
if_then(const lambda_functor& a1, const lambda_functor& a2) {
return
lambda_functor_base<
ifthen_action,
tuple
>
( tuple(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(args), CALL_ACTUAL_ARGS))
detail::select(boost::tuples::get(args), CALL_ACTUAL_ARGS);
else
detail::select(boost::tuples::get(args), CALL_ACTUAL_ARGS);
}
};
// If then else
template
inline const
lambda_functor<
lambda_functor_base<
ifthenelse_action,
tuple
>
>
if_then_else(const lambda_functor& a1, const lambda_functor& a2,
const lambda_functor& a3) {
return
lambda_functor_base<
ifthenelse_action,
tuple
>
(tuple
(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 {
// 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 {
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::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 {
typedef typename non_numeric_types::type type;
};
template
struct arithmetic_or_not {
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 {
typedef typename detail::array_to_pointer::type A1;
typedef typename detail::array_to_pointer::type B1;
typedef typename
boost::add_const::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 {
public:
Args args;
template struct sig {
private:
typedef typename detail::nth_return_type_sig::type ret1;
typedef typename detail::nth_return_type_sig::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(args), CALL_ACTUAL_ARGS)) ?
detail::select(boost::tuples::get(args), CALL_ACTUAL_ARGS)
:
detail::select(boost::tuples::get(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 typename as_lambda_functor::type> >
operator[](ElseT const& else_)
{
typedef if_then_else_composite typename as_lambda_functor::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 typename as_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