blob: 40fb5f0f99580df803797c212152488cbf71f1d8 [file] [log] [blame]
#ifndef BOOST_PP_IS_ITERATING
///////////////////////////////////////////////////////////////////////////////
/// \file poly_function.hpp
/// A wrapper that makes a tr1-style function object that handles const
/// and non-const refs and reference_wrapper arguments, too, and forwards
/// the arguments on to the specified implementation.
//
// Copyright 2008 Eric Niebler. 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)
#ifndef BOOST_PROTO_DETAIL_POLY_FUNCTION_EAN_2008_05_02
#define BOOST_PROTO_DETAIL_POLY_FUNCTION_EAN_2008_05_02
#include <boost/ref.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/void.hpp>
#include <boost/mpl/size_t.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/proto/proto_fwd.hpp>
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4181) // const applied to reference type
#endif
namespace boost { namespace proto { namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
struct normalize_arg
{
typedef T type;
typedef T const &reference;
};
template<typename T>
struct normalize_arg<T &>
{
typedef T type;
typedef T const &reference;
};
template<typename T>
struct normalize_arg<T const &>
{
typedef T type;
typedef T const &reference;
};
template<typename T>
struct normalize_arg<boost::reference_wrapper<T> >
{
typedef T &type;
typedef T &reference;
};
template<typename T>
struct normalize_arg<boost::reference_wrapper<T> &>
{
typedef T &type;
typedef T &reference;
};
template<typename T>
struct normalize_arg<boost::reference_wrapper<T> const &>
{
typedef T &type;
typedef T &reference;
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
struct arg
{
typedef T const &type;
arg(type t)
: value(t)
{}
operator type() const
{
return this->value;
}
type operator()() const
{
return *this;
}
private:
arg &operator =(arg const &);
type value;
};
template<typename T>
struct arg<T &>
{
typedef T &type;
arg(type t)
: value(t)
{}
operator type() const
{
return this->value;
}
type operator()() const
{
return *this;
}
private:
arg &operator =(arg const &);
type value;
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename T, typename Void = void>
struct is_poly_function
: mpl::false_
{};
template<typename T>
struct is_poly_function<T, typename T::is_poly_function_base_>
: mpl::true_
{};
////////////////////////////////////////////////////////////////////////////////////////////////
#define BOOST_PROTO_POLY_FUNCTION() \
typedef void is_poly_function_base_; \
/**/
////////////////////////////////////////////////////////////////////////////////////////////////
struct poly_function_base
{
/// INTERNAL ONLY
BOOST_PROTO_POLY_FUNCTION()
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Derived, typename NullaryResult = void>
struct poly_function
: poly_function_base
{
template<typename Sig>
struct result;
template<typename This>
struct result<This()>
: Derived::template impl<>
{
typedef typename result::result_type type;
};
NullaryResult operator()() const
{
result<Derived const()> impl;
return impl();
}
#define BOOST_PP_ITERATION_PARAMS_1 (4, (1, BOOST_PROTO_MAX_ARITY, <boost/proto/detail/poly_function.hpp>, 0))
#include BOOST_PP_ITERATE()
};
template<typename T>
struct wrap_t;
typedef char poly_function_t;
typedef char (&mono_function_t)[2];
typedef char (&unknown_function_t)[3];
template<typename T> poly_function_t test_poly_function(T *, wrap_t<typename T::is_poly_function_base_> * = 0);
template<typename T> mono_function_t test_poly_function(T *, wrap_t<typename T::result_type> * = 0);
template<typename T> unknown_function_t test_poly_function(T *, ...);
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Fun, typename Sig, typename Switch = mpl::size_t<sizeof(test_poly_function<Fun>(0,0))> >
struct poly_function_traits
{
typedef typename Fun::template result<Sig>::type result_type;
typedef Fun function_type;
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Fun, typename Sig>
struct poly_function_traits<Fun, Sig, mpl::size_t<sizeof(mono_function_t)> >
{
typedef typename Fun::result_type result_type;
typedef Fun function_type;
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename PolyFunSig, bool IsPolyFunction>
struct as_mono_function_impl;
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename PolyFunSig>
struct as_mono_function;
#define BOOST_PP_ITERATION_PARAMS_1 (4, (1, BOOST_PROTO_MAX_ARITY, <boost/proto/detail/poly_function.hpp>, 1))
#include BOOST_PP_ITERATE()
}}} // namespace boost::proto::detail
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#endif
#elif 0 == BOOST_PP_ITERATION_FLAGS()
#define N BOOST_PP_ITERATION()
template<typename This BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
struct result<This(BOOST_PP_ENUM_PARAMS(N, A))>
: Derived::template impl<
BOOST_PP_ENUM_BINARY_PARAMS(
N
, typename normalize_arg<A
, >::type BOOST_PP_INTERCEPT
)
>
{
typedef typename result::result_type type;
};
template<BOOST_PP_ENUM_PARAMS(N, typename A)>
typename result<
Derived const(
BOOST_PP_ENUM_BINARY_PARAMS(N, A, const & BOOST_PP_INTERCEPT)
)
>::type
operator ()(BOOST_PP_ENUM_BINARY_PARAMS(N, A, const &a)) const
{
result<
Derived const(
BOOST_PP_ENUM_BINARY_PARAMS(N, A, const & BOOST_PP_INTERCEPT)
)
> impl;
#define M0(Z, N, DATA) \
static_cast<typename normalize_arg<BOOST_PP_CAT(A, N) const &> \
::reference>(BOOST_PP_CAT(a, N))
return impl(BOOST_PP_ENUM(N, M0, ~));
#undef M0
}
#undef N
#elif 1 == BOOST_PP_ITERATION_FLAGS()
#define N BOOST_PP_ITERATION()
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename PolyFun BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
struct poly_function_traits<PolyFun, PolyFun(BOOST_PP_ENUM_PARAMS(N, A)), mpl::size_t<sizeof(poly_function_t)> >
{
typedef typename PolyFun::template impl<BOOST_PP_ENUM_PARAMS(N, const A)> function_type;
typedef typename function_type::result_type result_type;
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename PolyFun BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
struct as_mono_function_impl<PolyFun(BOOST_PP_ENUM_PARAMS(N, A)), true>
{
typedef typename PolyFun::template impl<BOOST_PP_ENUM_PARAMS(N, const A)> type;
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename PolyFun BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
struct as_mono_function_impl<PolyFun(BOOST_PP_ENUM_PARAMS(N, A)), false>
{
typedef PolyFun type;
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<typename PolyFun BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
struct as_mono_function<PolyFun(BOOST_PP_ENUM_PARAMS(N, A))>
: as_mono_function_impl<PolyFun(BOOST_PP_ENUM_PARAMS(N, A)), is_poly_function<PolyFun>::value>
{};
#undef N
#endif