270 lines
8.9 KiB
Plaintext
270 lines
8.9 KiB
Plaintext
// return_type_traits.hpp -- Boost Lambda Library ---------------------------
|
|
|
|
// Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi)
|
|
//
|
|
// 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
|
|
|
|
|
|
#ifndef BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP
|
|
#define BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP
|
|
|
|
#include "boost/mpl/has_xxx.hpp"
|
|
|
|
#include <cstddef> // needed for the ptrdiff_t
|
|
|
|
namespace boost {
|
|
namespace lambda {
|
|
|
|
// Much of the type deduction code for standard arithmetic types
|
|
// from Gary Powell
|
|
|
|
// different arities:
|
|
template <class Act, class A1> struct return_type_1; // 1-ary actions
|
|
template <class Act, class A1, class A2> struct return_type_2; // 2-ary
|
|
template <class Act, class Args> struct return_type_N; // >3- ary
|
|
|
|
template <class Act, class A1> struct return_type_1_prot;
|
|
template <class Act, class A1, class A2> struct return_type_2_prot; // 2-ary
|
|
template <class Act, class A1> struct return_type_N_prot; // >3-ary
|
|
|
|
|
|
namespace detail {
|
|
|
|
template<class> class return_type_deduction_failure {};
|
|
|
|
// In some cases return type deduction should fail (an invalid lambda
|
|
// expression). Sometimes the lambda expression can be ok, the return type
|
|
// just is not deducible (user defined operators). Then return type deduction
|
|
// should never be entered at all, and the use of ret<> does this.
|
|
// However, for nullary lambda functors, return type deduction is always
|
|
// entered, and there seems to be no way around this.
|
|
|
|
// (the return type is part of the prototype of the non-template
|
|
// operator()(). The prototype is instantiated, even though the body
|
|
// is not.)
|
|
|
|
// So, in the case the return type deduction should fail, it should not
|
|
// fail directly, but rather result in a valid but wrong return type,
|
|
// causing a compile time error only if the function is really called.
|
|
|
|
|
|
|
|
} // end detail
|
|
|
|
|
|
|
|
// return_type_X_prot classes --------------------------------------------
|
|
// These classes are the first layer that gets instantiated from the
|
|
// lambda_functor_base sig templates. It will check whether
|
|
// the action is protectable and one of arguments is "protected" or its
|
|
// evaluation will otherwise result in another lambda functor.
|
|
// If this is a case, the result type will be another lambda functor.
|
|
|
|
// The arguments are always non-reference types, except for comma action
|
|
// where the right argument can be a reference too. This is because it
|
|
// matters (in the builtin case) whether the argument is an lvalue or
|
|
// rvalue: int i; i, 1 -> rvalue; 1, i -> lvalue
|
|
|
|
template <class Act, class A> struct return_type_1_prot {
|
|
public:
|
|
typedef typename
|
|
detail::IF<
|
|
is_protectable<Act>::value && is_lambda_functor<A>::value,
|
|
lambda_functor<
|
|
lambda_functor_base<
|
|
Act,
|
|
tuple<typename detail::remove_reference_and_cv<A>::type>
|
|
>
|
|
>,
|
|
typename return_type_1<Act, A>::type
|
|
>::RET type;
|
|
};
|
|
|
|
// take care of the unavoidable instantiation for nullary case
|
|
template<class Act> struct return_type_1_prot<Act, null_type> {
|
|
typedef null_type type;
|
|
};
|
|
|
|
// Unary actions (result from unary operators)
|
|
// do not have a default return type.
|
|
template<class Act, class A> struct return_type_1 {
|
|
typedef typename
|
|
detail::return_type_deduction_failure<return_type_1> type;
|
|
};
|
|
|
|
|
|
namespace detail {
|
|
|
|
template <class T>
|
|
class protect_conversion {
|
|
typedef typename boost::remove_reference<T>::type non_ref_T;
|
|
public:
|
|
|
|
// add const to rvalues, so that all rvalues are stored as const in
|
|
// the args tuple
|
|
typedef typename detail::IF_type<
|
|
boost::is_reference<T>::value && !boost::is_const<non_ref_T>::value,
|
|
detail::identity_mapping<T>,
|
|
const_copy_argument<non_ref_T> // handles funtion and array
|
|
>::type type; // types correctly
|
|
};
|
|
|
|
} // end detail
|
|
|
|
template <class Act, class A, class B> struct return_type_2_prot {
|
|
|
|
// experimental feature
|
|
// We may have a lambda functor as a result type of a subexpression
|
|
// (if protect) has been used.
|
|
// Thus, if one of the parameter types is a lambda functor, the result
|
|
// is a lambda functor as well.
|
|
// We need to make a conservative choise here.
|
|
// The resulting lambda functor stores all const reference arguments as
|
|
// const copies. References to non-const are stored as such.
|
|
// So if the source of the argument is a const open argument, a bound
|
|
// argument stored as a const reference, or a function returning a
|
|
// const reference, that information is lost. There is no way of
|
|
// telling apart 'real const references' from just 'LL internal
|
|
// const references' (or it would be really hard)
|
|
|
|
// The return type is a subclass of lambda_functor, which has a converting
|
|
// copy constructor. It can copy any lambda functor, that has the same
|
|
// action type and code, and a copy compatible argument tuple.
|
|
|
|
|
|
typedef typename boost::remove_reference<A>::type non_ref_A;
|
|
typedef typename boost::remove_reference<B>::type non_ref_B;
|
|
|
|
typedef typename
|
|
detail::IF<
|
|
is_protectable<Act>::value &&
|
|
(is_lambda_functor<A>::value || is_lambda_functor<B>::value),
|
|
lambda_functor<
|
|
lambda_functor_base<
|
|
Act,
|
|
tuple<typename detail::protect_conversion<A>::type,
|
|
typename detail::protect_conversion<B>::type>
|
|
>
|
|
>,
|
|
typename return_type_2<Act, non_ref_A, non_ref_B>::type
|
|
>::RET type;
|
|
};
|
|
|
|
// take care of the unavoidable instantiation for nullary case
|
|
template<class Act> struct return_type_2_prot<Act, null_type, null_type> {
|
|
typedef null_type type;
|
|
};
|
|
// take care of the unavoidable instantiation for nullary case
|
|
template<class Act, class Other> struct return_type_2_prot<Act, Other, null_type> {
|
|
typedef null_type type;
|
|
};
|
|
// take care of the unavoidable instantiation for nullary case
|
|
template<class Act, class Other> struct return_type_2_prot<Act, null_type, Other> {
|
|
typedef null_type type;
|
|
};
|
|
|
|
// comma is a special case, as the user defined operator can return
|
|
// an lvalue (reference) too, hence it must be handled at this level.
|
|
template<class A, class B>
|
|
struct return_type_2_comma
|
|
{
|
|
typedef typename boost::remove_reference<A>::type non_ref_A;
|
|
typedef typename boost::remove_reference<B>::type non_ref_B;
|
|
|
|
typedef typename
|
|
detail::IF<
|
|
is_protectable<other_action<comma_action> >::value && // it is protectable
|
|
(is_lambda_functor<A>::value || is_lambda_functor<B>::value),
|
|
lambda_functor<
|
|
lambda_functor_base<
|
|
other_action<comma_action>,
|
|
tuple<typename detail::protect_conversion<A>::type,
|
|
typename detail::protect_conversion<B>::type>
|
|
>
|
|
>,
|
|
typename
|
|
return_type_2<other_action<comma_action>, non_ref_A, non_ref_B>::type
|
|
>::RET type1;
|
|
|
|
// if no user defined return_type_2 (or plain_return_type_2) specialization
|
|
// matches, then return the righthand argument
|
|
typedef typename
|
|
detail::IF<
|
|
boost::is_same<type1, detail::unspecified>::value,
|
|
B,
|
|
type1
|
|
>::RET type;
|
|
|
|
};
|
|
|
|
|
|
// currently there are no protectable actions with > 2 args
|
|
|
|
template<class Act, class Args> struct return_type_N_prot {
|
|
typedef typename return_type_N<Act, Args>::type type;
|
|
};
|
|
|
|
// take care of the unavoidable instantiation for nullary case
|
|
template<class Act> struct return_type_N_prot<Act, null_type> {
|
|
typedef null_type type;
|
|
};
|
|
|
|
// handle different kind of actions ------------------------
|
|
|
|
// use the return type given in the bind invocation as bind<Ret>(...)
|
|
template<int I, class Args, class Ret>
|
|
struct return_type_N<function_action<I, Ret>, Args> {
|
|
typedef Ret type;
|
|
};
|
|
|
|
// ::result_type support
|
|
|
|
namespace detail
|
|
{
|
|
|
|
BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type)
|
|
|
|
template<class F> struct get_result_type
|
|
{
|
|
typedef typename F::result_type type;
|
|
};
|
|
|
|
template<class F, class A> struct get_sig
|
|
{
|
|
typedef typename function_adaptor<F>::template sig<A>::type type;
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
// Ret is detail::unspecified, so try to deduce return type
|
|
template<int I, class Args>
|
|
struct return_type_N<function_action<I, detail::unspecified>, Args > {
|
|
|
|
// in the case of function action, the first element in Args is
|
|
// some type of function
|
|
typedef typename Args::head_type Func;
|
|
typedef typename detail::remove_reference_and_cv<Func>::type plain_Func;
|
|
|
|
public:
|
|
// pass the function to function_adaptor, and get the return type from
|
|
// that
|
|
typedef typename detail::IF<
|
|
detail::has_result_type<plain_Func>::value,
|
|
detail::get_result_type<plain_Func>,
|
|
detail::get_sig<plain_Func, Args>
|
|
>::RET::type type;
|
|
};
|
|
|
|
|
|
} // namespace lambda
|
|
} // namespace boost
|
|
|
|
#endif
|
|
|
|
|
|
|