454 lines
19 KiB
C++
454 lines
19 KiB
C++
#ifndef BOOST_PP_IS_ITERATING
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// \file make.hpp
|
|
/// Contains definition of the make<> transform.
|
|
//
|
|
// 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_TRANSFORM_MAKE_HPP_EAN_12_02_2007
|
|
#define BOOST_PROTO_TRANSFORM_MAKE_HPP_EAN_12_02_2007
|
|
|
|
#include <boost/proto/detail/prefix.hpp>
|
|
#include <boost/detail/workaround.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/preprocessor/repetition/enum_params_with_a_default.hpp>
|
|
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
|
#include <boost/preprocessor/facilities/intercept.hpp>
|
|
#include <boost/preprocessor/cat.hpp>
|
|
#include <boost/preprocessor/iteration/iterate.hpp>
|
|
#include <boost/preprocessor/selection/max.hpp>
|
|
#include <boost/preprocessor/arithmetic/inc.hpp>
|
|
#include <boost/mpl/aux_/has_type.hpp>
|
|
#include <boost/mpl/aux_/template_arity.hpp>
|
|
#include <boost/mpl/aux_/lambda_arity_param.hpp>
|
|
#include <boost/utility/result_of.hpp>
|
|
#include <boost/type_traits/remove_const.hpp>
|
|
#include <boost/type_traits/remove_reference.hpp>
|
|
#include <boost/proto/proto_fwd.hpp>
|
|
#include <boost/proto/traits.hpp>
|
|
#include <boost/proto/args.hpp>
|
|
#include <boost/proto/transform/impl.hpp>
|
|
#include <boost/proto/detail/as_lvalue.hpp>
|
|
#include <boost/proto/detail/ignore_unused.hpp>
|
|
#include <boost/proto/detail/suffix.hpp>
|
|
|
|
namespace boost { namespace proto
|
|
{
|
|
namespace detail
|
|
{
|
|
template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_PROTO_MAX_ARITY, typename A, void)>
|
|
struct typelist
|
|
{
|
|
typedef void type;
|
|
};
|
|
|
|
template<typename T, bool HasType = mpl::aux::has_type<T>::value>
|
|
struct nested_type
|
|
{
|
|
typedef typename T::type type;
|
|
};
|
|
|
|
template<typename T>
|
|
struct nested_type<T, false>
|
|
{
|
|
typedef T type;
|
|
};
|
|
|
|
template<typename T, typename Args, typename Void = void>
|
|
struct nested_type_if
|
|
: nested_type<T>
|
|
{};
|
|
|
|
template<typename R, typename Expr, typename State, typename Data
|
|
, bool IsTransform = is_callable<R>::value
|
|
>
|
|
struct make_if_;
|
|
|
|
template<typename R, typename Expr, typename State, typename Data
|
|
BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(long Arity = mpl::aux::template_arity<R>::value)
|
|
>
|
|
struct make_
|
|
{
|
|
typedef R type;
|
|
typedef void not_applied_;
|
|
};
|
|
|
|
template<typename R, typename Expr, typename State, typename Data>
|
|
struct make_if_<R, Expr, State, Data, false>
|
|
: make_<R, Expr, State, Data>
|
|
{};
|
|
|
|
#if BOOST_WORKAROUND(__GNUC__, == 3) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0)
|
|
// work around GCC bug
|
|
template<typename Tag, typename Args, long N, typename Expr, typename State, typename Data>
|
|
struct make_if_<proto::expr<Tag, Args, N>, Expr, State, Data, false>
|
|
{
|
|
typedef proto::expr<Tag, Args, N> type;
|
|
typedef void not_applied_;
|
|
};
|
|
#endif
|
|
|
|
// TODO could optimize this if R is a transform
|
|
template<typename R, typename Expr, typename State, typename Data>
|
|
struct make_if_<R, Expr, State, Data, true>
|
|
: remove_const<typename remove_reference<
|
|
typename boost::result_of<R(Expr, State, Data)>::type
|
|
>::type>
|
|
{};
|
|
|
|
template<typename Type, bool IsAggregate = is_aggregate<Type>::value>
|
|
struct construct_
|
|
{
|
|
typedef Type result_type;
|
|
|
|
Type operator ()() const
|
|
{
|
|
return Type();
|
|
}
|
|
|
|
#define TMP(Z, N, DATA) \
|
|
template<BOOST_PP_ENUM_PARAMS_Z(Z, N, typename A)> \
|
|
Type operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, &a)) const \
|
|
{ \
|
|
return Type(BOOST_PP_ENUM_PARAMS_Z(Z, N, a)); \
|
|
}
|
|
BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), TMP, ~)
|
|
#undef TMP
|
|
};
|
|
|
|
template<typename Type>
|
|
struct construct_<Type, true>
|
|
{
|
|
typedef Type result_type;
|
|
|
|
Type operator ()() const
|
|
{
|
|
return Type();
|
|
}
|
|
|
|
#define TMP(Z, N, DATA) \
|
|
template<BOOST_PP_ENUM_PARAMS_Z(Z, N, typename A)> \
|
|
Type operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, &a)) const \
|
|
{ \
|
|
Type that = {BOOST_PP_ENUM_PARAMS_Z(Z, N, a)}; \
|
|
return that; \
|
|
}
|
|
BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PROTO_MAX_ARITY), TMP, ~)
|
|
#undef TMP
|
|
};
|
|
|
|
#define TMP(Z, N, DATA) \
|
|
template<typename Type BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, typename A)> \
|
|
Type construct(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, &a)) \
|
|
{ \
|
|
return construct_<Type>()(BOOST_PP_ENUM_PARAMS_Z(Z, N, a)); \
|
|
}
|
|
BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, TMP, ~)
|
|
#undef TMP
|
|
}
|
|
|
|
/// \brief A PrimitiveTransform which prevents another PrimitiveTransform
|
|
/// from being applied in an \c ObjectTransform.
|
|
///
|
|
/// When building higher order transforms with <tt>make\<\></tt> or
|
|
/// <tt>lazy\<\></tt>, you sometimes would like to build types that
|
|
/// are parameterized with Proto transforms. In such lambda-style
|
|
/// transforms, Proto will unhelpfully find all nested transforms
|
|
/// and apply them, even if you don't want them to be applied. Consider
|
|
/// the following transform, which will replace the \c _ in
|
|
/// <tt>Bar<_>()</tt> with <tt>proto::terminal\<int\>::type</tt>:
|
|
///
|
|
/// \code
|
|
/// template<typename T>
|
|
/// struct Bar
|
|
/// {};
|
|
///
|
|
/// struct Foo
|
|
/// : proto::when<_, Bar<_>() >
|
|
/// {};
|
|
///
|
|
/// proto::terminal<int>::type i = {0};
|
|
///
|
|
/// int main()
|
|
/// {
|
|
/// Foo()(i);
|
|
/// std::cout << typeid(Foo()(i)).name() << std::endl;
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// If you actually wanted to default-construct an object of type
|
|
/// <tt>Bar\<_\></tt>, you would have to protect the \c _ to prevent
|
|
/// it from being applied. You can use <tt>proto::protect\<\></tt>
|
|
/// as follows:
|
|
///
|
|
/// \code
|
|
/// // OK: replace anything with Bar<_>()
|
|
/// struct Foo
|
|
/// : proto::when<_, Bar<protect<_> >() >
|
|
/// {};
|
|
/// \endcode
|
|
template<typename PrimitiveTransform>
|
|
struct protect : transform<protect<PrimitiveTransform> >
|
|
{
|
|
template<typename, typename, typename>
|
|
struct impl
|
|
{
|
|
typedef PrimitiveTransform result_type;
|
|
};
|
|
};
|
|
|
|
/// \brief A PrimitiveTransform which computes a type by evaluating any
|
|
/// nested transforms and then constructs an object of that type.
|
|
///
|
|
/// The <tt>make\<\></tt> transform checks to see if \c Object is a template.
|
|
/// If it is, the template type is disassembled to find nested transforms.
|
|
/// Proto considers the following types to represent transforms:
|
|
///
|
|
/// \li Function types
|
|
/// \li Function pointer types
|
|
/// \li Types for which <tt>proto::is_callable\< type \>::::value</tt> is \c true
|
|
///
|
|
/// <tt>make\<T\<X0,X1,...\> \>::::result\<void(Expr, State, Data)\>::::type</tt>
|
|
/// is evaluated as follows. For each \c X in <tt>X0,X1,...</tt>, do:
|
|
///
|
|
/// \li If \c X is a template like <tt>U\<Y0,Y1,...\></tt>, then let <tt>X'</tt>
|
|
/// be <tt>make\<U\<Y0,Y1,...\> \>::::result\<void(Expr, State, Data)\>::::type</tt>
|
|
/// (which evaluates this procedure recursively). Note whether any
|
|
/// substitutions took place during this operation.
|
|
/// \li Otherwise, if \c X is a transform, then let <tt>X'</tt> be
|
|
/// <tt>when\<_, X\>::::result\<void(Expr, State, Data)\>::::type</tt>.
|
|
/// Note that a substitution took place.
|
|
/// \li Otherwise, let <tt>X'</tt> be \c X, and note that no substitution
|
|
/// took place.
|
|
/// \li If any substitutions took place in any of the above steps and
|
|
/// <tt>T\<X0',X1',...\></tt> has a nested <tt>::type</tt> typedef,
|
|
/// the result type is <tt>T\<X0',X1',...\>::::type</tt>.
|
|
/// \li Otherwise, the result type is <tt>T\<X0',X1',...\></tt>.
|
|
///
|
|
/// Note that <tt>when\<\></tt> is implemented in terms of <tt>call\<\></tt>
|
|
/// and <tt>make\<\></tt>, so the above procedure is evaluated recursively.
|
|
template<typename Object>
|
|
struct make : transform<make<Object> >
|
|
{
|
|
template<typename Expr, typename State, typename Data>
|
|
struct impl : transform_impl<Expr, State, Data>
|
|
{
|
|
typedef typename detail::make_if_<Object, Expr, State, Data>::type result_type;
|
|
|
|
/// \return <tt>result_type()</tt>
|
|
result_type operator ()(
|
|
typename impl::expr_param
|
|
, typename impl::state_param
|
|
, typename impl::data_param
|
|
) const
|
|
{
|
|
return result_type();
|
|
}
|
|
};
|
|
};
|
|
|
|
#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, BOOST_PROTO_MAX_ARITY, <boost/proto/transform/make.hpp>))
|
|
#include BOOST_PP_ITERATE()
|
|
|
|
/// INTERNAL ONLY
|
|
///
|
|
template<typename Object>
|
|
struct is_callable<make<Object> >
|
|
: mpl::true_
|
|
{};
|
|
|
|
/// INTERNAL ONLY
|
|
///
|
|
template<typename PrimitiveTransform>
|
|
struct is_callable<protect<PrimitiveTransform> >
|
|
: mpl::true_
|
|
{};
|
|
}}
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#define N BOOST_PP_ITERATION()
|
|
|
|
namespace detail
|
|
{
|
|
#if N > 0
|
|
template<typename T BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
|
|
struct nested_type_if<
|
|
T
|
|
, typelist<BOOST_PP_ENUM_PARAMS(N, A)>
|
|
, typename typelist<
|
|
BOOST_PP_ENUM_BINARY_PARAMS(N, typename A, ::not_applied_ BOOST_PP_INTERCEPT)
|
|
>::type
|
|
>
|
|
{
|
|
typedef T type;
|
|
typedef void not_applied_;
|
|
};
|
|
|
|
#define TMP0(Z, M, DATA) make_if_<BOOST_PP_CAT(A, M), Expr, State, Data>
|
|
#define TMP1(Z, M, DATA) typename TMP0(Z, M, DATA) ::type
|
|
|
|
template<
|
|
template<BOOST_PP_ENUM_PARAMS(N, typename BOOST_PP_INTERCEPT)> class R
|
|
BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)
|
|
, typename Expr, typename State, typename Data
|
|
>
|
|
struct make_<R<BOOST_PP_ENUM_PARAMS(N, A)>, Expr, State, Data
|
|
BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(N)
|
|
>
|
|
: nested_type_if<
|
|
R<BOOST_PP_ENUM(N, TMP1, ~)>
|
|
, typelist<BOOST_PP_ENUM(N, TMP0, ~) >
|
|
>
|
|
{};
|
|
|
|
template<
|
|
template<BOOST_PP_ENUM_PARAMS(N, typename BOOST_PP_INTERCEPT)> class R
|
|
BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)
|
|
, typename Expr, typename State, typename Data
|
|
>
|
|
struct make_<noinvoke<R<BOOST_PP_ENUM_PARAMS(N, A)> >, Expr, State, Data
|
|
BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(N)
|
|
>
|
|
{
|
|
typedef R<BOOST_PP_ENUM(N, TMP1, ~)> type;
|
|
};
|
|
|
|
#undef TMP0
|
|
#undef TMP1
|
|
#endif
|
|
|
|
template<
|
|
typename R
|
|
BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)
|
|
, typename Expr, typename State, typename Data
|
|
>
|
|
struct make_if_<R(BOOST_PP_ENUM_PARAMS(N, A)), Expr, State, Data, false>
|
|
{
|
|
typedef
|
|
typename remove_const<
|
|
typename remove_reference<
|
|
typename when<_, R(BOOST_PP_ENUM_PARAMS(N, A))>
|
|
::template impl<Expr, State, Data>::result_type
|
|
>::type
|
|
>::type
|
|
type;
|
|
};
|
|
|
|
template<
|
|
typename R
|
|
BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)
|
|
, typename Expr, typename State, typename Data
|
|
>
|
|
struct make_if_<R(*)(BOOST_PP_ENUM_PARAMS(N, A)), Expr, State, Data, false>
|
|
{
|
|
typedef
|
|
typename remove_const<
|
|
typename remove_reference<
|
|
typename when<_, R(BOOST_PP_ENUM_PARAMS(N, A))>
|
|
::template impl<Expr, State, Data>::result_type
|
|
>::type
|
|
>::type
|
|
type;
|
|
};
|
|
|
|
template<typename T, typename A>
|
|
struct construct_<proto::expr<T, A, N>, true>
|
|
{
|
|
typedef proto::expr<T, A, N> result_type;
|
|
|
|
template<BOOST_PP_ENUM_PARAMS(BOOST_PP_MAX(N, 1), typename A)>
|
|
result_type operator ()(BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_MAX(N, 1), A, &a)) const
|
|
{
|
|
return result_type::make(BOOST_PP_ENUM_PARAMS(BOOST_PP_MAX(N, 1), a));
|
|
}
|
|
};
|
|
}
|
|
|
|
/// \brief A PrimitiveTransform which computes a type by evaluating any
|
|
/// nested transforms and then constructs an object of that type with the
|
|
/// current expression, state and data, transformed according
|
|
/// to \c A0 through \c AN.
|
|
template<typename Object BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
|
|
struct make<Object(BOOST_PP_ENUM_PARAMS(N, A))>
|
|
: transform<make<Object(BOOST_PP_ENUM_PARAMS(N, A))> >
|
|
{
|
|
template<typename Expr, typename State, typename Data>
|
|
struct impl : transform_impl<Expr, State, Data>
|
|
{
|
|
/// \brief <tt>make\<Object\>::::result\<void(Expr, State, Data)\>::::type</tt>
|
|
typedef typename detail::make_if_<Object, Expr, State, Data>::type result_type;
|
|
//typedef typename detail::make_<Object, Expr, State, Data>::type result_type;
|
|
|
|
/// Let \c ax be <tt>when\<_, Ax\>()(e, s, d)</tt>
|
|
/// for each \c x in <tt>[0,N]</tt>.
|
|
/// Let \c T be <tt>result\<void(Expr, State, Data)\>::::type</tt>.
|
|
/// Return <tt>T(a0, a1,... aN)</tt>.
|
|
///
|
|
/// \param e The current expression
|
|
/// \param s The current state
|
|
/// \param d An arbitrary data
|
|
result_type operator ()(
|
|
typename impl::expr_param e
|
|
, typename impl::state_param s
|
|
, typename impl::data_param d
|
|
) const
|
|
{
|
|
proto::detail::ignore_unused(e);
|
|
proto::detail::ignore_unused(s);
|
|
proto::detail::ignore_unused(d);
|
|
return detail::construct<result_type>(
|
|
#define TMP(Z, M, DATA) \
|
|
detail::as_lvalue( \
|
|
typename when<_, BOOST_PP_CAT(A, M)> \
|
|
::template impl<Expr, State, Data>()(e, s, d) \
|
|
)
|
|
BOOST_PP_ENUM(N, TMP, DATA)
|
|
#undef TMP
|
|
);
|
|
}
|
|
};
|
|
};
|
|
|
|
#if BOOST_WORKAROUND(__GNUC__, == 3) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0)
|
|
// work around GCC bug
|
|
template<typename Tag, typename Args, long Arity BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A)>
|
|
struct make<proto::expr<Tag, Args, Arity>(BOOST_PP_ENUM_PARAMS(N, A))>
|
|
: transform<make<proto::expr<Tag, Args, Arity>(BOOST_PP_ENUM_PARAMS(N, A))> >
|
|
{
|
|
template<typename Expr, typename State, typename Data>
|
|
struct impl : transform_impl<Expr, State, Data>
|
|
{
|
|
typedef proto::expr<Tag, Args, Arity> result_type;
|
|
|
|
result_type operator ()(
|
|
typename impl::expr_param e
|
|
, typename impl::state_param s
|
|
, typename impl::data_param d
|
|
) const
|
|
{
|
|
return proto::expr<Tag, Args, Arity>::make(
|
|
#define TMP(Z, M, DATA) \
|
|
detail::as_lvalue( \
|
|
typename when<_, BOOST_PP_CAT(A, M)> \
|
|
::template impl<Expr, State, Data>()(e, s, d) \
|
|
)
|
|
BOOST_PP_ENUM(N, TMP, DATA)
|
|
#undef TMP
|
|
);
|
|
}
|
|
};
|
|
};
|
|
#endif
|
|
|
|
#undef N
|
|
|
|
#endif
|