feat():initial version

This commit is contained in:
2026-06-09 20:16:47 +08:00
commit 85fbb3188c
14809 changed files with 3044607 additions and 0 deletions

View File

@@ -0,0 +1,736 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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_YAP_ALGORITHM_HPP_INCLUDED
#define BOOST_YAP_ALGORITHM_HPP_INCLUDED
#include <boost/yap/algorithm_fwd.hpp>
#include <boost/yap/user_macros.hpp>
#include <boost/yap/detail/algorithm.hpp>
#include <boost/hana/size.hpp>
#include <boost/hana/comparing.hpp>
namespace boost { namespace yap {
#ifdef BOOST_NO_CONSTEXPR_IF
namespace detail {
template<typename Expr, bool MutableRvalueRef>
struct deref_impl
{
constexpr decltype(auto) operator()(Expr && expr)
{
return std::move(*expr.elements[hana::llong_c<0>]);
}
};
template<typename Expr>
struct deref_impl<Expr, false>
{
constexpr decltype(auto) operator()(Expr && expr)
{
return *expr.elements[hana::llong_c<0>];
}
};
}
#endif
/** "Dereferences" a reference-expression, forwarding its referent to
the caller. */
template<typename Expr>
constexpr decltype(auto) deref(Expr && expr)
{
static_assert(
is_expr<Expr>::value, "deref() is only defined for expressions.");
static_assert(
detail::remove_cv_ref_t<Expr>::kind == expr_kind::expr_ref,
"deref() is only defined for expr_ref-kind expressions.");
#ifdef BOOST_NO_CONSTEXPR_IF
return detail::deref_impl < Expr,
std::is_rvalue_reference<Expr>::value &&
!std::is_const<std::remove_reference_t<Expr>>::value >
{}(static_cast<Expr &&>(expr));
#else
using namespace hana::literals;
if constexpr (
std::is_rvalue_reference<Expr>::value &&
!std::is_const<std::remove_reference_t<Expr>>::value) {
return std::move(*expr.elements[0_c]);
} else {
return *expr.elements[0_c];
}
#endif
}
namespace detail {
template<typename Tuple, long long I>
struct lvalue_ref_ith_element
: std::is_lvalue_reference<decltype(
std::declval<Tuple>()[hana::llong<I>{}])>
{
};
#ifdef BOOST_NO_CONSTEXPR_IF
template<bool ValueOfTerminalsOnly, typename T>
constexpr decltype(auto) value_impl(T && x);
template<
typename T,
bool IsExprRef,
bool ValueOfTerminalsOnly,
bool TakeValue,
bool IsLvalueRef>
struct value_expr_impl;
template<
typename T,
bool ValueOfTerminalsOnly,
bool TakeValue,
bool IsLvalueRef>
struct value_expr_impl<
T,
true,
ValueOfTerminalsOnly,
TakeValue,
IsLvalueRef>
{
constexpr decltype(auto) operator()(T && x)
{
return ::boost::yap::detail::value_impl<ValueOfTerminalsOnly>(
::boost::yap::deref(static_cast<T &&>(x)));
}
};
template<typename T, bool ValueOfTerminalsOnly>
struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, true>
{
constexpr decltype(auto) operator()(T && x)
{
return x.elements[hana::llong_c<0>];
}
};
template<typename T, bool ValueOfTerminalsOnly>
struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, false>
{
constexpr decltype(auto) operator()(T && x)
{
return std::move(x.elements[hana::llong_c<0>]);
}
};
template<typename T, bool ValueOfTerminalsOnly, bool IsLvalueRef>
struct value_expr_impl<
T,
false,
ValueOfTerminalsOnly,
false,
IsLvalueRef>
{
constexpr decltype(auto) operator()(T && x)
{
return static_cast<T &&>(x);
}
};
template<typename T, bool IsExpr, bool ValueOfTerminalsOnly>
struct value_impl_t
{
constexpr decltype(auto) operator()(T && x)
{
constexpr expr_kind kind = detail::remove_cv_ref_t<T>::kind;
constexpr detail::expr_arity arity = detail::arity_of<kind>();
return value_expr_impl < T, kind == expr_kind::expr_ref,
ValueOfTerminalsOnly,
(ValueOfTerminalsOnly && kind == expr_kind::terminal) ||
(!ValueOfTerminalsOnly &&
arity == detail::expr_arity::one),
std::is_lvalue_reference<T>::value ||
detail::lvalue_ref_ith_element<
decltype(x.elements),
0>::value > {}(static_cast<T &&>(x));
}
};
template<typename T, bool ValueOfTerminalsOnly>
struct value_impl_t<T, false, ValueOfTerminalsOnly>
{
constexpr decltype(auto) operator()(T && x)
{
return static_cast<T &&>(x);
}
};
template<bool ValueOfTerminalsOnly, typename T>
constexpr decltype(auto) value_impl(T && x)
{
return detail::
value_impl_t<T, is_expr<T>::value, ValueOfTerminalsOnly>{}(
static_cast<T &&>(x));
}
#else
template<bool ValueOfTerminalsOnly, typename T>
constexpr decltype(auto) value_impl(T && x)
{
if constexpr (is_expr<T>::value) {
using namespace hana::literals;
constexpr expr_kind kind = remove_cv_ref_t<T>::kind;
constexpr expr_arity arity = arity_of<kind>();
if constexpr (kind == expr_kind::expr_ref) {
return value_impl<ValueOfTerminalsOnly>(
::boost::yap::deref(static_cast<T &&>(x)));
} else if constexpr (
kind == expr_kind::terminal ||
(!ValueOfTerminalsOnly && arity == expr_arity::one)) {
if constexpr (
std::is_lvalue_reference<T>::value ||
detail::
lvalue_ref_ith_element<decltype(x.elements), 0>{}) {
return x.elements[0_c];
} else {
return std::move(x.elements[0_c]);
}
} else {
return static_cast<T &&>(x);
}
} else {
return static_cast<T &&>(x);
}
}
#endif
}
/** Forwards the sole element of \a x to the caller, possibly calling
<code>deref()</code> first if \a x is a reference expression, or
forwards \a x to the caller unchanged.
More formally:
- If \a x is not an expression, \a x is forwarded to the caller.
- Otherwise, if \a x is a reference expression, the result is
<code>value(deref(x))</code>.
- Otherwise, if \a x is an expression with only one value (a unary
expression or a terminal expression), the result is the forwarded
first element of \a x.
- Otherwise, \a x is forwarded to the caller. */
template<typename T>
constexpr decltype(auto) value(T && x)
{
return detail::value_impl<false>(static_cast<T &&>(x));
}
#ifdef BOOST_NO_CONSTEXPR_IF
template<typename Expr, typename I>
constexpr decltype(auto) get(Expr && expr, I const & i);
namespace detail {
template<long long I, typename Expr, bool IsExpr, bool IsLvalueRef>
struct get_impl;
template<long long I, typename Expr, bool IsLvalueRef>
struct get_impl<I, Expr, true, IsLvalueRef>
{
constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
{
return ::boost::yap::get(
::boost::yap::deref(static_cast<Expr &&>(expr)), i);
}
};
template<long long I, typename Expr>
struct get_impl<I, Expr, false, true>
{
constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
{
return expr.elements[i];
}
};
template<long long I, typename Expr>
struct get_impl<I, Expr, false, false>
{
constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
{
return std::move(expr.elements[i]);
}
};
}
#endif
/** Forwards the <i>i</i>-th element of \a expr to the caller. If \a
expr is a reference expression, the result is <code>get(deref(expr),
i)</code>.
\note <code>get()</code> is only valid if \a Expr is an expression.
*/
template<typename Expr, typename I>
constexpr decltype(auto) get(Expr && expr, I const & i)
{
static_assert(
is_expr<Expr>::value, "get() is only defined for expressions.");
static_assert(
hana::IntegralConstant<I>::value,
"'i' must be an IntegralConstant");
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
static_assert(
kind == expr_kind::expr_ref ||
(0 <= I::value &&
I::value < decltype(hana::size(expr.elements))::value),
"In get(expr, I), I must be a valid index into expr's tuple "
"elements.");
#ifdef BOOST_NO_CONSTEXPR_IF
return detail::get_impl<
I::value,
Expr,
kind == expr_kind::expr_ref,
std::is_lvalue_reference<Expr>::value>{}(static_cast<Expr &&>(expr), i);
#else
using namespace hana::literals;
if constexpr (kind == expr_kind::expr_ref) {
return ::boost::yap::get(
::boost::yap::deref(static_cast<Expr &&>(expr)), i);
} else {
if constexpr (std::is_lvalue_reference<Expr>::value) {
return expr.elements[i];
} else {
return std::move(expr.elements[i]);
}
}
#endif
}
/** Returns <code>get(expr, boost::hana::llong_c<I>)</code>. */
template<long long I, typename Expr>
constexpr decltype(auto) get_c(Expr && expr)
{
return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<I>);
}
/** Returns the left operand in a binary operator expression.
Equivalent to <code>get(expr, 0_c)</code>.
\note <code>left()</code> is only valid if \a Expr is a binary
operator expression.
*/
template<typename Expr>
constexpr decltype(auto) left(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c);
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
static_assert(
kind == expr_kind::expr_ref ||
detail::arity_of<kind>() == detail::expr_arity::two,
"left() is only defined for binary expressions.");
}
/** Returns the right operand in a binary operator expression.
Equivalent to <code>get(expr, 1_c)</code>.
\note <code>right()</code> is only valid if \a Expr is a binary
operator expression.
*/
template<typename Expr>
constexpr decltype(auto) right(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c);
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
static_assert(
kind == expr_kind::expr_ref ||
detail::arity_of<kind>() == detail::expr_arity::two,
"right() is only defined for binary expressions.");
}
/** Returns the condition expression in an if_else expression.
Equivalent to <code>get(expr, 0_c)</code>.
\note <code>cond()</code> is only valid if \a Expr is an
<code>expr_kind::if_else</code> expression.
*/
template<typename Expr>
constexpr decltype(auto) cond(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c);
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
static_assert(
kind == expr_kind::expr_ref || kind == expr_kind::if_else,
"cond() is only defined for if_else expressions.");
}
/** Returns the then-expression in an if_else expression.
Equivalent to <code>get(expr, 1_c)</code>.
\note <code>then()</code> is only valid if \a Expr is an
<code>expr_kind::if_else</code> expression.
*/
template<typename Expr>
constexpr decltype(auto) then(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c);
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
static_assert(
kind == expr_kind::expr_ref || kind == expr_kind::if_else,
"then() is only defined for if_else expressions.");
}
/** Returns the else-expression in an if_else expression.
Equivalent to <code>get(expr, 2_c)</code>.
\note <code>else_()</code> is only valid if \a Expr is an
<code>expr_kind::if_else</code> expression.
*/
template<typename Expr>
constexpr decltype(auto) else_(Expr && expr)
{
using namespace hana::literals;
return ::boost::yap::get(static_cast<Expr &&>(expr), 2_c);
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
static_assert(
kind == expr_kind::expr_ref || kind == expr_kind::if_else,
"else_() is only defined for if_else expressions.");
}
/** Returns the callable in a call expression.
Equivalent to <code>get(expr, 0)</code>.
\note <code>callable()</code> is only valid if \a Expr is an
<code>expr_kind::call</code> expression.
*/
template<typename Expr>
constexpr decltype(auto) callable(Expr && expr)
{
return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<0>);
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
static_assert(
kind == expr_kind::expr_ref ||
detail::arity_of<kind>() == detail::expr_arity::n,
"callable() is only defined for call expressions.");
}
/** Returns the <i>i-th</i> argument expression in a call expression.
Equivalent to <code>get(expr, i + 1)</code>.
\note <code>argument()</code> is only valid if \a Expr is an
<code>expr_kind::call</code> expression.
*/
template<long long I, typename Expr>
constexpr decltype(auto) argument(Expr && expr, hana::llong<I> i)
{
return ::boost::yap::get(
static_cast<Expr &&>(expr), hana::llong_c<I + 1>);
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
static_assert(
kind == expr_kind::expr_ref ||
detail::arity_of<kind>() == detail::expr_arity::n,
"argument() is only defined for call expressions.");
static_assert(
kind == expr_kind::expr_ref ||
(0 <= I && I < decltype(hana::size(expr.elements))::value - 1),
"I must be a valid call-expression argument index.");
}
/** Makes a new expression instantiated from the expression template \a
ExprTemplate, of kind \a Kind, with the given values as its
elements.
For each parameter P:
- If P is an expression, P is moved into the result if P is an
rvalue and captured by reference into the result otherwise.
- Otherwise, P is wrapped in a terminal expression.
\note <code>make_expression()</code> is only valid if the number of
parameters passed is appropriate for \a Kind.
*/
template<
template<expr_kind, class> class ExprTemplate,
expr_kind Kind,
typename... T>
constexpr auto make_expression(T &&... t)
{
constexpr detail::expr_arity arity = detail::arity_of<Kind>();
static_assert(
(arity == detail::expr_arity::one && sizeof...(T) == 1) ||
(arity == detail::expr_arity::two && sizeof...(T) == 2) ||
(arity == detail::expr_arity::three && sizeof...(T) == 3) ||
arity == detail::expr_arity::n,
"The number of parameters passed to make_expression() must "
"match the arity "
"implied by the expr_kind template parameter.");
using tuple_type =
hana::tuple<detail::operand_type_t<ExprTemplate, T>...>;
return ExprTemplate<Kind, tuple_type>{tuple_type{
detail::make_operand<detail::operand_type_t<ExprTemplate, T>>{}(
static_cast<T &&>(t))...}};
}
/** Makes a new terminal expression instantiated from the expression
template \a ExprTemplate, with the given value as its sole element.
\note <code>make_terminal()</code> is only valid if \a T is \b not
an expression.
*/
template<template<expr_kind, class> class ExprTemplate, typename T>
constexpr auto make_terminal(T && t)
{
static_assert(
!is_expr<T>::value,
"make_terminal() is only defined for non expressions.");
using result_type = detail::operand_type_t<ExprTemplate, T>;
using tuple_type = decltype(std::declval<result_type>().elements);
return result_type{tuple_type{static_cast<T &&>(t)}};
}
#ifdef BOOST_NO_CONSTEXPR_IF
namespace detail {
template<
template<expr_kind, class> class ExprTemplate,
typename T,
bool IsExpr>
struct as_expr_impl
{
constexpr decltype(auto) operator()(T && t)
{
return static_cast<T &&>(t);
}
};
template<template<expr_kind, class> class ExprTemplate, typename T>
struct as_expr_impl<ExprTemplate, T, false>
{
constexpr decltype(auto) operator()(T && t)
{
return make_terminal<ExprTemplate>(static_cast<T &&>(t));
}
};
}
#endif
/** Returns an expression formed from \a t as follows:
- If \a t is an expression, \a t is forwarded to the caller.
- Otherwise, \a t is wrapped in a terminal expression.
*/
template<template<expr_kind, class> class ExprTemplate, typename T>
constexpr decltype(auto) as_expr(T && t)
{
#ifdef BOOST_NO_CONSTEXPR_IF
return detail::as_expr_impl<ExprTemplate, T, is_expr<T>::value>{}(
static_cast<T &&>(t));
#else
if constexpr (is_expr<T>::value) {
return static_cast<T &&>(t);
} else {
return make_terminal<ExprTemplate>(static_cast<T &&>(t));
}
#endif
}
/** A callable type that evaluates its contained expression when called.
\see <code>make_expression_function()</code>
*/
template<typename Expr>
struct expression_function
{
template<typename... U>
constexpr decltype(auto) operator()(U &&... u)
{
return ::boost::yap::evaluate(expr, static_cast<U &&>(u)...);
}
Expr expr;
};
namespace detail {
template<expr_kind Kind, typename Tuple>
struct expression_function_expr
{
static const expr_kind kind = Kind;
Tuple elements;
};
}
/** Returns a callable object that \a expr has been forwarded into. This
is useful for using expressions as function objects.
Lvalue expressions are stored in the result by reference; rvalue
expressions are moved into the result.
\note <code>make_expression_function()</code> is only valid if \a
Expr is an expression.
*/
template<typename Expr>
constexpr auto make_expression_function(Expr && expr)
{
static_assert(
is_expr<Expr>::value,
"make_expression_function() is only defined for expressions.");
using stored_type =
detail::operand_type_t<detail::expression_function_expr, Expr &&>;
return expression_function<stored_type>{
detail::make_operand<stored_type>{}(static_cast<Expr &&>(expr))};
}
}}
#include <boost/yap/detail/transform.hpp>
namespace boost { namespace yap {
/** Returns a transform object that replaces placeholders within an
expression with the given values.
*/
template<typename... T>
constexpr auto replacements(T &&... t)
{
return detail::placeholder_transform_t<T...>(static_cast<T &&>(t)...);
}
/** Returns \a expr with the placeholders replaced by YAP terminals
containing the given values.
\note <code>replace_placeholders(expr, t...)</code> is only valid if
\a expr is an expression, and <code>max_p <= sizeof...(t)</code>,
where <code>max_p</code> is the maximum placeholder index in \a expr.
*/
template<typename Expr, typename... T>
constexpr decltype(auto) replace_placeholders(Expr && expr, T &&... t)
{
static_assert(
is_expr<Expr>::value,
"evaluate() is only defined for expressions.");
return transform(
static_cast<Expr &&>(expr), replacements(static_cast<T &&>(t)...));
}
/** Returns a transform object that evaluates an expression using the
built-in semantics. The transform replaces any placeholders with the
given values.
*/
template<typename... T>
constexpr auto evaluation(T &&... t)
{
return detail::evaluation_transform_t<T...>(static_cast<T &&>(t)...);
}
/** Evaluates \a expr using the built-in semantics, replacing any
placeholders with the given values.
\note <code>evaluate(expr)</code> is only valid if \a expr is an
expression.
*/
template<typename Expr, typename... T>
constexpr decltype(auto) evaluate(Expr && expr, T &&... t)
{
static_assert(
is_expr<Expr>::value,
"evaluate() is only defined for expressions.");
return transform(
static_cast<Expr &&>(expr), evaluation(static_cast<T &&>(t)...));
}
namespace detail {
template<typename... Transforms>
constexpr auto make_transform_tuple(Transforms &... transforms)
{
return hana::tuple<Transforms *...>{&transforms...};
}
template<bool Strict>
struct transform_
{
template<typename Expr, typename Transform, typename... Transforms>
constexpr decltype(auto) operator()(
Expr && expr, Transform & transform, Transforms &... transforms) const
{
auto transform_tuple =
detail::make_transform_tuple(transform, transforms...);
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
return detail::
transform_impl<Strict, 0, kind == expr_kind::expr_ref>{}(
static_cast<Expr &&>(expr), transform_tuple);
}
};
}
/** Returns the result of transforming (all or part of) \a expr using
whatever overloads of <code>Transform::operator()</code> match \a
expr.
\note Transformations can do anything: they may have side effects;
they may mutate values; they may mutate types; and they may do any
combination of these.
*/
template<typename Expr, typename Transform, typename... Transforms>
constexpr decltype(auto)
transform(Expr && expr, Transform && transform, Transforms &&... transforms)
{
static_assert(
is_expr<Expr>::value,
"transform() is only defined for expressions.");
return detail::transform_<false>{}(
static_cast<Expr &&>(expr), transform, transforms...);
}
/** Returns the result of transforming \a expr using whichever overload of
<code>Transform::operator()</code> best matches \a expr. If no
overload of <code>Transform::operator()</code> matches, a compile-time
error results.
\note Transformations can do anything: they may have side effects;
they may mutate values; they may mutate types; and they may do any
combination of these.
*/
template<typename Expr, typename Transform, typename... Transforms>
constexpr decltype(auto) transform_strict(
Expr && expr, Transform && transform, Transforms &&... transforms)
{
static_assert(
is_expr<Expr>::value,
"transform() is only defined for expressions.");
return detail::transform_<true>{}(
static_cast<Expr &&>(expr), transform, transforms...);
}
}}
#endif

View File

@@ -0,0 +1,214 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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_YAP_ALGORITHM_FWD_HPP_INCLUDED
#define BOOST_YAP_ALGORITHM_FWD_HPP_INCLUDED
#include <boost/yap/config.hpp>
#include <boost/hana/integral_constant.hpp>
#include <boost/hana/tuple.hpp>
#include <boost/hana/core/is_a.hpp>
namespace boost { namespace yap {
/** The enumeration representing all the kinds of expressions supported in
YAP.
*/
enum class expr_kind {
expr_ref =
0, ///< A (possibly \c const) reference to another expression.
terminal = 1, ///< A terminal expression.
// unary
unary_plus = 2, ///< \c +
negate = 3, ///< \c -
dereference = 4, ///< \c *
complement = 5, ///< \c ~
address_of = 6, ///< \c &
logical_not = 7, ///< \c !
pre_inc = 8, ///< \c ++
pre_dec = 9, ///< \c \-\-
post_inc = 10, ///< \c ++(int)
post_dec = 11, ///< \c \-\-(int)
// binary
shift_left = 12, ///< \c <<
shift_right = 13, ///< \c >>
multiplies = 14, ///< \c *
divides = 15, ///< \c /
modulus = 16, ///< \c %
plus = 17, ///< \c +
minus = 18, ///< \c -
less = 19, ///< \c <
greater = 20, ///< \c >
less_equal = 21, ///< \c <=
greater_equal = 22, ///< \c >=
equal_to = 23, ///< \c ==
not_equal_to = 24, ///< \c !=
logical_or = 25, ///< \c ||
logical_and = 26, ///< \c &&
bitwise_and = 27, ///< \c &
bitwise_or = 28, ///< \c |
bitwise_xor = 29, ///< \c ^
comma = 30, ///< \c ,
mem_ptr = 31, ///< \c ->*
assign = 32, ///< \c =
shift_left_assign = 33, ///< \c <<=
shift_right_assign = 34, ///< \c >>=
multiplies_assign = 35, ///< \c *=
divides_assign = 36, ///< \c /=
modulus_assign = 37, ///< \c %=
plus_assign = 38, ///< \c +=
minus_assign = 39, ///< \c -=
bitwise_and_assign = 40, ///< \c &=
bitwise_or_assign = 41, ///< \c |=
bitwise_xor_assign = 42, ///< \c ^=
subscript = 43, ///< \c []
// ternary
if_else = 44, ///< Analogous to \c ?: .
// n-ary
call = 45 ///< \c ()
};
/** The type used to represent the index of a placeholder terminal. */
template<long long I>
struct placeholder : hana::llong<I>
{
};
#ifdef BOOST_YAP_DOXYGEN
/** A metafunction that evaluates to std::true_type if \a Expr is an
Expression, and std::false_type otherwise. */
template<typename Expr>
struct is_expr;
#else
template<expr_kind Kind, typename Tuple>
struct expression;
namespace detail {
// void_t
template<class...>
using void_t = void;
// remove_cv_ref
template<typename T>
struct remove_cv_ref : std::remove_cv<std::remove_reference_t<T>>
{
};
template<typename T>
using remove_cv_ref_t = typename remove_cv_ref<T>::type;
}
template<
typename Expr,
typename = detail::void_t<>,
typename = detail::void_t<>>
struct is_expr : std::false_type
{
};
template<typename Expr>
struct is_expr<
Expr,
detail::void_t<decltype(detail::remove_cv_ref_t<Expr>::kind)>,
detail::void_t<decltype(std::declval<Expr>().elements)>>
: std::integral_constant<
bool,
std::is_same<
std::remove_cv_t<decltype(
detail::remove_cv_ref_t<Expr>::kind)>,
expr_kind>::value &&
hana::is_a<
hana::tuple_tag,
decltype(std::declval<Expr>().elements)>>
{
};
#endif // BOOST_YAP_DOXYGEN
/** A convenience alias for a terminal expression holding a \a T,
instantiated from expression template \a expr_template. */
template<template<expr_kind, class> class expr_template, typename T>
using terminal = expr_template<expr_kind::terminal, hana::tuple<T>>;
/** A convenience alias for a reference expression holding an expression
\a T, instantiated from expression template \a expr_template. */
template<template<expr_kind, class> class expr_template, typename T>
using expression_ref = expr_template<
expr_kind::expr_ref,
hana::tuple<std::remove_reference_t<T> *>>;
#ifndef BOOST_YAP_DOXYGEN
template<typename Expr, typename... T>
constexpr decltype(auto) evaluate(Expr && expr, T &&... t);
template<typename Expr, typename Transform, typename... Transforms>
constexpr decltype(auto) transform(
Expr && expr, Transform && transform, Transforms &&... transforms);
template<typename Expr, typename Transform, typename... Transforms>
constexpr decltype(auto) transform_strict(
Expr && expr, Transform && transform, Transforms &&... transforms);
template<typename T>
constexpr decltype(auto) deref(T && x);
template<typename Expr>
constexpr decltype(auto) value(Expr && expr);
#endif // BOOST_YAP_DOXYGEN
namespace literals {
/** Creates literal placeholders. Placeholder indices are 1-based. */
template<char... c>
constexpr auto operator"" _p()
{
using i = hana::llong<hana::ic_detail::parse<sizeof...(c)>({c...})>;
static_assert(1 <= i::value, "Placeholders must be >= 1.");
return expression<
expr_kind::terminal,
hana::tuple<placeholder<i::value>>>{};
}
}
/** Used as the tag-type passed to a transform function written in the
tag-transform form. */
template<expr_kind Kind>
struct expr_tag
{
static const expr_kind kind = Kind;
};
/** Used as the expression template returned by some operations inside YAP
when YAP does not have an expression template it was told to use. For
instance, if transform() creates a new expression by transforming an
existing expression's elements, it will attempt to create the new
expression using the existing one's expression template. If no such
template exists because the existing expression was not made from an
expression template, minimal_expr is used. */
template<expr_kind Kind, typename Tuple>
struct minimal_expr
{
static expr_kind const kind = Kind;
Tuple elements;
};
}}
#endif

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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_YAP_CONFIG_HPP_INCLUDED
#define BOOST_YAP_CONFIG_HPP_INCLUDED
#ifndef BOOST_NO_CONSTEXPR_IF
/** Indicates whether the compiler supports constexpr if.
If the user does not define any value for this, we assume that the
compiler does not have the necessary support. Note that this is a
temporary hack; this should eventually be a Boost-wide macro. */
#define BOOST_NO_CONSTEXPR_IF
#elif BOOST_NO_CONSTEXPR_IF == 0
#undef BOOST_NO_CONSTEXPR_IF
#endif
#endif

View File

@@ -0,0 +1,598 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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_YAP_DETAIL_EXPRESSION_HPP_INCLUDED
#define BOOST_YAP_DETAIL_EXPRESSION_HPP_INCLUDED
#include <boost/yap/algorithm_fwd.hpp>
#include <boost/hana/size.hpp>
#include <boost/hana/tuple.hpp>
#include <memory>
#include <type_traits>
namespace boost { namespace yap { namespace detail {
// static_const
template<typename T>
struct static_const
{
static constexpr T value{};
};
template<typename T>
constexpr T static_const<T>::value;
// partial_decay
template<typename T>
struct partial_decay
{
using type = T;
};
template<typename T>
struct partial_decay<T[]>
{
using type = T *;
};
template<typename T, std::size_t N>
struct partial_decay<T[N]>
{
using type = T *;
};
template<typename T>
struct partial_decay<T (&)[]>
{
using type = T *;
};
template<typename T, std::size_t N>
struct partial_decay<T (&)[N]>
{
using type = T *;
};
template<typename R, typename... A>
struct partial_decay<R(A...)>
{
using type = R (*)(A...);
};
template<typename R, typename... A>
struct partial_decay<R(A..., ...)>
{
using type = R (*)(A..., ...);
};
template<typename R, typename... A>
struct partial_decay<R (&)(A...)>
{
using type = R (*)(A...);
};
template<typename R, typename... A>
struct partial_decay<R (&)(A..., ...)>
{
using type = R (*)(A..., ...);
};
template<typename R, typename... A>
struct partial_decay<R (*&)(A...)>
{
using type = R (*)(A...);
};
template<typename R, typename... A>
struct partial_decay<R (*&)(A..., ...)>
{
using type = R (*)(A..., ...);
};
// operand_value_type_phase_1
template<
typename T,
typename U = typename detail::partial_decay<T>::type,
bool AddRValueRef = std::is_same<T, U>::value && !std::is_const<U>::value>
struct operand_value_type_phase_1;
template<typename T, typename U>
struct operand_value_type_phase_1<T, U, true>
{
using type = U &&;
};
template<typename T, typename U>
struct operand_value_type_phase_1<T, U, false>
{
using type = U;
};
// expr_ref
template<template<expr_kind, class> class ExprTemplate, typename T>
struct expr_ref
{
using type = expression_ref<ExprTemplate, T>;
};
template<template<expr_kind, class> class ExprTemplate, typename Tuple>
struct expr_ref<ExprTemplate, ExprTemplate<expr_kind::expr_ref, Tuple> &>
{
using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
};
template<template<expr_kind, class> class ExprTemplate, typename Tuple>
struct expr_ref<
ExprTemplate,
ExprTemplate<expr_kind::expr_ref, Tuple> const &>
{
using type = ExprTemplate<expr_kind::expr_ref, Tuple>;
};
template<template<expr_kind, class> class ExprTemplate, typename T>
using expr_ref_t = typename expr_ref<ExprTemplate, T>::type;
template<template<expr_kind, class> class ExprTemplate, typename T>
struct expr_ref_tuple;
template<template<expr_kind, class> class ExprTemplate, typename Tuple>
struct expr_ref_tuple<
ExprTemplate,
ExprTemplate<expr_kind::expr_ref, Tuple>>
{
using type = Tuple;
};
template<template<expr_kind, class> class ExprTemplate, typename T>
using expr_ref_tuple_t = typename expr_ref_tuple<ExprTemplate, T>::type;
// operand_type
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U = typename operand_value_type_phase_1<T>::type,
bool RemoveRefs = std::is_rvalue_reference<U>::value,
bool IsExpr = is_expr<T>::value,
bool IsLRef = std::is_lvalue_reference<T>::value>
struct operand_type;
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
bool RemoveRefs>
struct operand_type<ExprTemplate, T, U, RemoveRefs, true, false>
{
using type = remove_cv_ref_t<T>;
};
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
bool RemoveRefs>
struct operand_type<ExprTemplate, T, U, RemoveRefs, true, true>
{
using type = expr_ref_t<ExprTemplate, T>;
};
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
bool RemoveRefs,
bool IsLRef>
struct operand_type<ExprTemplate, T, U, RemoveRefs, true, IsLRef>
{
using type = remove_cv_ref_t<T>;
};
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
bool IsLRef>
struct operand_type<ExprTemplate, T, U, true, false, IsLRef>
{
using type = terminal<ExprTemplate, std::remove_reference_t<U>>;
};
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
bool IsLRef>
struct operand_type<ExprTemplate, T, U, false, false, IsLRef>
{
using type = terminal<ExprTemplate, U>;
};
template<template<expr_kind, class> class ExprTemplate, typename T>
using operand_type_t = typename operand_type<ExprTemplate, T>::type;
// make_operand
template<typename T>
struct make_operand
{
template<typename U>
constexpr auto operator()(U && u)
{
return T{static_cast<U &&>(u)};
}
};
template<template<expr_kind, class> class ExprTemplate, typename Tuple>
struct make_operand<ExprTemplate<expr_kind::expr_ref, Tuple>>
{
constexpr auto operator()(ExprTemplate<expr_kind::expr_ref, Tuple> expr)
{
return expr;
}
template<typename U>
constexpr auto operator()(U && u)
{
return ExprTemplate<expr_kind::expr_ref, Tuple>{
Tuple{std::addressof(u)}};
}
};
// free_binary_op_result
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U,
bool TNonExprUExpr = !is_expr<T>::value && is_expr<U>::value,
bool ULvalueRef = std::is_lvalue_reference<U>::value>
struct free_binary_op_result;
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U>
struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, true>
{
using lhs_type = operand_type_t<ExprTemplate, T>;
using rhs_type = expr_ref_t<ExprTemplate, U>;
using rhs_tuple_type = expr_ref_tuple_t<ExprTemplate, rhs_type>;
using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
};
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U>
struct free_binary_op_result<ExprTemplate, OpKind, T, U, true, false>
{
using lhs_type = operand_type_t<ExprTemplate, T>;
using rhs_type = remove_cv_ref_t<U>;
using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
};
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U>
using free_binary_op_result_t =
typename free_binary_op_result<ExprTemplate, OpKind, T, U>::type;
// ternary_op_result
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
typename V,
bool Valid =
is_expr<T>::value || is_expr<U>::value || is_expr<V>::value>
struct ternary_op_result;
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
typename V>
struct ternary_op_result<ExprTemplate, T, U, V, true>
{
using cond_type = operand_type_t<ExprTemplate, T>;
using then_type = operand_type_t<ExprTemplate, U>;
using else_type = operand_type_t<ExprTemplate, V>;
using type = ExprTemplate<
expr_kind::if_else,
hana::tuple<cond_type, then_type, else_type>>;
};
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
typename V>
using ternary_op_result_t =
typename ternary_op_result<ExprTemplate, T, U, V>::type;
// udt_any_ternary_op_result
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
typename V,
template<class> class UdtTrait,
bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
!is_expr<V>::value &&
(UdtTrait<remove_cv_ref_t<T>>::value ||
UdtTrait<remove_cv_ref_t<U>>::value ||
UdtTrait<remove_cv_ref_t<V>>::value)>
struct udt_any_ternary_op_result;
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
typename V,
template<class> class UdtTrait>
struct udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait, true>
{
using cond_type = operand_type_t<ExprTemplate, T>;
using then_type = operand_type_t<ExprTemplate, U>;
using else_type = operand_type_t<ExprTemplate, V>;
using type = ExprTemplate<
expr_kind::if_else,
hana::tuple<cond_type, then_type, else_type>>;
};
template<
template<expr_kind, class> class ExprTemplate,
typename T,
typename U,
typename V,
template<class> class UdtTrait>
using udt_any_ternary_op_result_t =
typename udt_any_ternary_op_result<ExprTemplate, T, U, V, UdtTrait>::
type;
// udt_unary_op_result
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
template<class> class UdtTrait,
bool Valid = !is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value>
struct udt_unary_op_result;
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
template<class> class UdtTrait>
struct udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait, true>
{
using x_type = operand_type_t<ExprTemplate, T>;
using type = ExprTemplate<OpKind, hana::tuple<x_type>>;
};
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
template<class> class UdtTrait>
using udt_unary_op_result_t =
typename udt_unary_op_result<ExprTemplate, OpKind, T, UdtTrait>::type;
// udt_udt_binary_op_result
template<typename T, template<class> class UdtTrait>
struct is_udt_arg
{
static bool const value =
!is_expr<T>::value && UdtTrait<remove_cv_ref_t<T>>::value;
};
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U,
template<class> class TUdtTrait,
template<class> class UUdtTrait,
bool Valid =
is_udt_arg<T, TUdtTrait>::value && is_udt_arg<U, UUdtTrait>::value>
struct udt_udt_binary_op_result;
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U,
template<class> class TUdtTrait,
template<class> class UUdtTrait>
struct udt_udt_binary_op_result<
ExprTemplate,
OpKind,
T,
U,
TUdtTrait,
UUdtTrait,
true>
{
using lhs_type = operand_type_t<ExprTemplate, T>;
using rhs_type = operand_type_t<ExprTemplate, U>;
using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
};
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U,
template<class> class TUdtTrait,
template<class> class UUdtTrait>
using udt_udt_binary_op_result_t = typename udt_udt_binary_op_result<
ExprTemplate,
OpKind,
T,
U,
TUdtTrait,
UUdtTrait>::type;
// udt_any_binary_op_result
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U,
template<class> class UdtTrait,
bool Valid = !is_expr<T>::value && !is_expr<U>::value &&
(UdtTrait<remove_cv_ref_t<T>>::value ||
UdtTrait<remove_cv_ref_t<U>>::value)>
struct udt_any_binary_op_result;
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U,
template<class> class UdtTrait>
struct udt_any_binary_op_result<ExprTemplate, OpKind, T, U, UdtTrait, true>
{
using lhs_type = operand_type_t<ExprTemplate, T>;
using rhs_type = operand_type_t<ExprTemplate, U>;
using type = ExprTemplate<OpKind, hana::tuple<lhs_type, rhs_type>>;
};
template<
template<expr_kind, class> class ExprTemplate,
expr_kind OpKind,
typename T,
typename U,
template<class> class UdtTrait>
using udt_any_binary_op_result_t = typename udt_any_binary_op_result<
ExprTemplate,
OpKind,
T,
U,
UdtTrait>::type;
// not_copy_or_move
template<typename LeftT, typename RightT>
struct copy_or_move : std::false_type
{
};
template<typename T>
struct copy_or_move<T, T const &> : std::true_type
{
};
template<typename T>
struct copy_or_move<T, T &> : std::true_type
{
};
template<typename T>
struct copy_or_move<T, T &&> : std::true_type
{
};
// expr_arity
enum class expr_arity { invalid, one, two, three, n };
template<expr_kind Kind>
constexpr expr_arity arity_of()
{
switch (Kind) {
case expr_kind::expr_ref:
case expr_kind::terminal:
// unary
case expr_kind::unary_plus: // +
case expr_kind::negate: // -
case expr_kind::dereference: // *
case expr_kind::complement: // ~
case expr_kind::address_of: // &
case expr_kind::logical_not: // !
case expr_kind::pre_inc: // ++
case expr_kind::pre_dec: // --
case expr_kind::post_inc: // ++(int)
case expr_kind::post_dec: // --(int)
return expr_arity::one;
// binary
case expr_kind::shift_left: // <<
case expr_kind::shift_right: // >>
case expr_kind::multiplies: // *
case expr_kind::divides: // /
case expr_kind::modulus: // %
case expr_kind::plus: // +
case expr_kind::minus: // -
case expr_kind::less: // <
case expr_kind::greater: // >
case expr_kind::less_equal: // <=
case expr_kind::greater_equal: // >=
case expr_kind::equal_to: // ==
case expr_kind::not_equal_to: // !=
case expr_kind::logical_or: // ||
case expr_kind::logical_and: // &&
case expr_kind::bitwise_and: // &
case expr_kind::bitwise_or: // |
case expr_kind::bitwise_xor: // ^
case expr_kind::comma: // :
case expr_kind::mem_ptr: // ->*
case expr_kind::assign: // =
case expr_kind::shift_left_assign: // <<=
case expr_kind::shift_right_assign: // >>=
case expr_kind::multiplies_assign: // *=
case expr_kind::divides_assign: // /=
case expr_kind::modulus_assign: // %=
case expr_kind::plus_assign: // +=
case expr_kind::minus_assign: // -=
case expr_kind::bitwise_and_assign: // &=
case expr_kind::bitwise_or_assign: // |=
case expr_kind::bitwise_xor_assign: // ^=
case expr_kind::subscript: // []
return expr_arity::two;
// ternary
case expr_kind::if_else: // (analogous to) ?:
return expr_arity::three;
// n-ary
case expr_kind::call: // ()
return expr_arity::n;
default: return expr_arity::invalid;
}
}
}}}
#endif

View File

@@ -0,0 +1,591 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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_YAP_DETAIL_TRANSFORM_HPP_INCLUDED
#define BOOST_YAP_DETAIL_TRANSFORM_HPP_INCLUDED
#include <boost/yap/algorithm_fwd.hpp>
#include <boost/hana/transform.hpp>
#include <cassert>
namespace boost { namespace yap { namespace detail {
template<int I, typename T, typename... Ts>
struct nth_element_impl
{
using type = typename nth_element_impl<I - 1, Ts...>::type;
};
template<typename T, typename... Ts>
struct nth_element_impl<0, T, Ts...>
{
using type = T;
};
template<int I, typename... Ts>
using nth_element = typename nth_element_impl<I, Ts...>::type;
template<typename T, bool RemoveRefs = std::is_rvalue_reference<T>::value>
struct rvalue_ref_to_value;
template<typename T>
struct rvalue_ref_to_value<T, true>
{
using type = typename std::remove_reference<T>::type;
};
template<typename T>
struct rvalue_ref_to_value<T, false>
{
using type = T;
};
template<typename T>
using rvalue_ref_to_value_t = typename rvalue_ref_to_value<T>::type;
template<bool IsRvalueRef>
struct rvalue_mover
{
template<typename T>
constexpr decltype(auto) operator()(T && t) const
{
return static_cast<T &&>(t);
}
};
template<>
struct rvalue_mover<true>
{
template<typename T>
constexpr std::remove_reference_t<T> operator()(T && t) const
{
return std::move(t);
}
};
template<typename... PlaceholderArgs>
struct placeholder_transform_t
{
using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;
constexpr placeholder_transform_t(PlaceholderArgs &&... args) :
placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)
{}
template<long long I>
constexpr decltype(auto)
operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const
{
static_assert(
I <= decltype(hana::size(std::declval<tuple_t>()))::value,
"Out of range placeholder index,");
using nth_type = nth_element<I - 1, PlaceholderArgs...>;
return as_expr<minimal_expr>(
rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(
placeholder_args_[hana::llong<I - 1>{}]));
}
tuple_t placeholder_args_;
};
template<typename... PlaceholderArgs>
struct evaluation_transform_t
{
using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;
constexpr evaluation_transform_t(PlaceholderArgs &&... args) :
placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)
{}
template<long long I>
constexpr decltype(auto)
operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const
{
static_assert(
I <= decltype(hana::size(std::declval<tuple_t>()))::value,
"Out of range placeholder index,");
using nth_type = nth_element<I - 1, PlaceholderArgs...>;
return rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(
placeholder_args_[hana::llong<I - 1>{}]);
}
template<typename T>
constexpr decltype(auto) operator()(expr_tag<expr_kind::terminal>, T && t) const
{
return static_cast<T &&>(t);
}
#define BOOST_YAP_UNARY_OPERATOR_CASE(op, op_name) \
template<typename T> \
constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t) const \
{ \
return op transform( \
as_expr<minimal_expr>(static_cast<T &&>(t)), *this); \
}
BOOST_YAP_UNARY_OPERATOR_CASE(+, unary_plus)
BOOST_YAP_UNARY_OPERATOR_CASE(-, negate)
BOOST_YAP_UNARY_OPERATOR_CASE(*, dereference)
BOOST_YAP_UNARY_OPERATOR_CASE(~, complement)
BOOST_YAP_UNARY_OPERATOR_CASE(&, address_of)
BOOST_YAP_UNARY_OPERATOR_CASE(!, logical_not)
BOOST_YAP_UNARY_OPERATOR_CASE(++, pre_inc)
BOOST_YAP_UNARY_OPERATOR_CASE(--, pre_dec)
template<typename T>
constexpr decltype(auto) operator()(expr_tag<expr_kind::post_inc>, T && t) const
{
return transform(
as_expr<minimal_expr>(static_cast<T &&>(t)), *this)++;
}
template<typename T>
constexpr decltype(auto) operator()(expr_tag<expr_kind::post_dec>, T && t) const
{
return transform(
as_expr<minimal_expr>(static_cast<T &&>(t)), *this)--;
}
#undef BOOST_YAP_UNARY_OPERATOR_CASE
#define BOOST_YAP_BINARY_OPERATOR_CASE(op, op_name) \
template<typename T, typename U> \
constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t, U && u) const \
{ \
return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this) \
op transform(as_expr<minimal_expr>(static_cast<U &&>(u)), *this); \
}
BOOST_YAP_BINARY_OPERATOR_CASE(<<, shift_left)
BOOST_YAP_BINARY_OPERATOR_CASE(>>, shift_right)
BOOST_YAP_BINARY_OPERATOR_CASE(*, multiplies)
BOOST_YAP_BINARY_OPERATOR_CASE(/, divides)
BOOST_YAP_BINARY_OPERATOR_CASE(%, modulus)
BOOST_YAP_BINARY_OPERATOR_CASE(+, plus)
BOOST_YAP_BINARY_OPERATOR_CASE(-, minus)
BOOST_YAP_BINARY_OPERATOR_CASE(<, less)
BOOST_YAP_BINARY_OPERATOR_CASE(>, greater)
BOOST_YAP_BINARY_OPERATOR_CASE(<=, less_equal)
BOOST_YAP_BINARY_OPERATOR_CASE(>=, greater_equal)
BOOST_YAP_BINARY_OPERATOR_CASE(==, equal_to)
BOOST_YAP_BINARY_OPERATOR_CASE(!=, not_equal_to)
BOOST_YAP_BINARY_OPERATOR_CASE(||, logical_or)
BOOST_YAP_BINARY_OPERATOR_CASE(&&, logical_and)
BOOST_YAP_BINARY_OPERATOR_CASE(&, bitwise_and)
BOOST_YAP_BINARY_OPERATOR_CASE(|, bitwise_or)
BOOST_YAP_BINARY_OPERATOR_CASE (^, bitwise_xor)
// clang-format off
//[ evaluation_transform_comma
template<typename T, typename U>
constexpr decltype(auto) operator()(expr_tag<expr_kind::comma>, T && t, U && u) const
{
return transform(
as_expr<minimal_expr>(static_cast<T &&>(t)), *this),
transform(
as_expr<minimal_expr>(static_cast<U &&>(u)), *this);
}
//]
// clang-format on
BOOST_YAP_BINARY_OPERATOR_CASE(->*, mem_ptr)
BOOST_YAP_BINARY_OPERATOR_CASE(=, assign)
BOOST_YAP_BINARY_OPERATOR_CASE(<<=, shift_left_assign)
BOOST_YAP_BINARY_OPERATOR_CASE(>>=, shift_right_assign)
BOOST_YAP_BINARY_OPERATOR_CASE(*=, multiplies_assign)
BOOST_YAP_BINARY_OPERATOR_CASE(/=, divides_assign)
BOOST_YAP_BINARY_OPERATOR_CASE(%=, modulus_assign)
BOOST_YAP_BINARY_OPERATOR_CASE(+=, plus_assign)
BOOST_YAP_BINARY_OPERATOR_CASE(-=, minus_assign)
BOOST_YAP_BINARY_OPERATOR_CASE(&=, bitwise_and_assign)
BOOST_YAP_BINARY_OPERATOR_CASE(|=, bitwise_or_assign)
BOOST_YAP_BINARY_OPERATOR_CASE(^=, bitwise_xor_assign)
template<typename T, typename U>
constexpr decltype(auto)
operator()(expr_tag<expr_kind::subscript>, T && t, U && u) const
{
return transform(
as_expr<minimal_expr>(static_cast<T &&>(t)), *this)[transform(
as_expr<minimal_expr>(static_cast<U &&>(u)), *this)];
}
#undef BOOST_YAP_BINARY_OPERATOR_CASE
template<typename T, typename U, typename V>
constexpr decltype(auto)
operator()(expr_tag<expr_kind::if_else>, T && t, U && u, V && v) const
{
return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this)
? transform(
as_expr<minimal_expr>(static_cast<U &&>(u)), *this)
: transform(
as_expr<minimal_expr>(static_cast<V &&>(v)),
*this);
}
// clang-format off
//[ evaluation_transform_call
template<typename Callable, typename... Args>
constexpr decltype(auto) operator()(
expr_tag<expr_kind::call>, Callable && callable, Args &&... args) const
{
return transform(as_expr<minimal_expr>(static_cast<Callable &&>(callable)), *this)(
transform(as_expr<minimal_expr>(static_cast<Args &&>(args)), *this)...
);
}
//]
// clang-format on
tuple_t placeholder_args_;
};
template<bool Strict, int I, bool IsExprRef>
struct transform_impl;
template<
bool Strict,
typename Expr,
typename TransformTuple,
int I,
expr_arity Arity,
typename = void_t<>>
struct transform_expression_tag;
// Forward terminals/recurively transform noterminasl; attempted last.
template<bool IsLvalueRef, bool IsTerminal, bool Strict>
struct default_transform
{
template<typename Expr, typename TransformTuple>
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
return static_cast<Expr &&>(expr);
}
};
template<bool IsLvalueRef, bool IsTerminal>
struct default_transform<IsLvalueRef, IsTerminal, true>
{
struct incomplete;
// If you're getting an error because this function is uncallable,
// that's by design. You called yap::transform_strict(expr, xfrom)
// and one or more subexpression of 'expr' are not callable with any
// overload in 'xform'.
template<typename Expr, typename TransformTuple>
constexpr incomplete operator()(Expr && expr, TransformTuple transforms) const;
};
template<
expr_kind Kind,
template<expr_kind, class> class ExprTemplate,
typename OldTuple,
typename NewTuple>
constexpr auto make_expr_from_tuple(
ExprTemplate<Kind, OldTuple> const & expr, NewTuple && tuple)
{
return ExprTemplate<Kind, NewTuple>{std::move(tuple)};
}
template<expr_kind Kind, typename Expr, typename NewTuple>
constexpr auto make_expr_from_tuple(Expr const & expr, NewTuple && tuple)
{
return minimal_expr<Kind, NewTuple>{std::move(tuple)};
}
template<typename Expr, typename Tuple, typename TransformTuple>
constexpr decltype(auto) transform_nonterminal(
Expr const & expr, Tuple && tuple, TransformTuple transforms)
{
auto transformed_tuple =
hana::transform(static_cast<Tuple &&>(tuple), [&](auto && element) {
using element_t = decltype(element);
auto const kind = remove_cv_ref_t<element_t>::kind;
::boost::yap::detail::
transform_impl<false, 0, kind == expr_kind::expr_ref>
xform;
return xform(static_cast<element_t &&>(element), transforms);
});
auto const kind = remove_cv_ref_t<Expr>::kind;
return make_expr_from_tuple<kind>(expr, std::move(transformed_tuple));
}
template<>
struct default_transform<true, false, false>
{
template<typename Expr, typename TransformTuple>
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
return transform_nonterminal(expr, expr.elements, transforms);
}
};
template<>
struct default_transform<false, false, false>
{
template<typename Expr, typename TransformTuple>
constexpr decltype(auto)
operator()(Expr && expr, TransformTuple transforms) const
{
return transform_nonterminal(
expr, std::move(expr.elements), transforms);
}
};
// Dispatch to the next transform, or to the default transform if there is
// no next transform.
template<
bool Strict,
typename Expr,
typename TransformTuple,
int I,
bool NextTransformExists>
struct next_or_default_transform
{
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
// Use the next transform.
constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;
return detail::
transform_impl<Strict, I + 1, kind == expr_kind::expr_ref>{}(
static_cast<Expr &&>(expr), transforms);
}
};
template<bool Strict, typename Expr, typename TransformTuple, int I>
struct next_or_default_transform<Strict, Expr, TransformTuple, I, false>
{
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
// No next transform exists; use the default transform.
constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;
return default_transform<
std::is_lvalue_reference<Expr>::value,
kind == expr_kind::terminal,
Strict>{}(static_cast<Expr &&>(expr), transforms);
}
};
// Expression-matching; attempted second.
template<
bool Strict,
typename Expr,
typename TransformTuple,
int I,
typename = detail::void_t<>>
struct transform_expression_expr
{
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
// No expr-matching succeeded; use the next or default transform.
return next_or_default_transform<
Strict,
Expr,
TransformTuple,
I,
I + 1 < decltype(hana::size(
std::declval<TransformTuple>()))::value>{}(
static_cast<Expr &&>(expr), transforms);
}
};
template<bool Strict, typename Expr, typename TransformTuple, int I>
struct transform_expression_expr<
Strict,
Expr,
TransformTuple,
I,
void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
std::declval<Expr>()))>>
{
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
return (*transforms[hana::llong<I>{}])(static_cast<Expr &&>(expr));
}
};
// Tag-matching; attempted first.
template<
bool Strict,
typename Expr,
typename TransformTuple,
int I,
expr_arity Arity,
typename>
struct transform_expression_tag
{
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
// No tag-matching succeeded; try expr-matching.
return transform_expression_expr<Strict, Expr, TransformTuple, I>{}(
static_cast<Expr &&>(expr), transforms);
}
};
template<typename T>
constexpr decltype(auto) terminal_value(T && x)
{
return value_impl<true>(static_cast<T &&>(x));
}
template<bool Strict, typename Expr, typename TransformTuple, int I>
struct transform_expression_tag<
Strict,
Expr,
TransformTuple,
I,
expr_arity::one,
void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
expr_tag<remove_cv_ref_t<Expr>::kind>{},
terminal_value(::boost::yap::value(std::declval<Expr>()))))>>
{
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
return (*transforms[hana::llong<I>{}])(
expr_tag<remove_cv_ref_t<Expr>::kind>{},
terminal_value(
::boost::yap::value(static_cast<Expr &&>(expr))));
}
};
template<bool Strict, typename Expr, typename TransformTuple, int I>
struct transform_expression_tag<
Strict,
Expr,
TransformTuple,
I,
expr_arity::two,
void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
expr_tag<remove_cv_ref_t<Expr>::kind>{},
terminal_value(::boost::yap::left(std::declval<Expr>())),
terminal_value(::boost::yap::right(std::declval<Expr>()))))>>
{
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
return (*transforms[hana::llong<I>{}])(
expr_tag<remove_cv_ref_t<Expr>::kind>{},
terminal_value(::boost::yap::left(static_cast<Expr &&>(expr))),
terminal_value(
::boost::yap::right(static_cast<Expr &&>(expr))));
}
};
template<bool Strict, typename Expr, typename TransformTuple, int I>
struct transform_expression_tag<
Strict,
Expr,
TransformTuple,
I,
expr_arity::three,
void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
expr_tag<remove_cv_ref_t<Expr>::kind>{},
terminal_value(::boost::yap::cond(std::declval<Expr>())),
terminal_value(::boost::yap::then(std::declval<Expr>())),
terminal_value(::boost::yap::else_(std::declval<Expr>()))))>>
{
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
return (*transforms[hana::llong<I>{}])(
expr_tag<remove_cv_ref_t<Expr>::kind>{},
terminal_value(::boost::yap::cond(static_cast<Expr &&>(expr))),
terminal_value(::boost::yap::then(static_cast<Expr &&>(expr))),
terminal_value(
::boost::yap::else_(static_cast<Expr &&>(expr))));
}
};
template<typename Expr, typename Transform>
struct transform_call_unpacker
{
template<long long... I>
constexpr auto operator()(
Expr && expr,
Transform & transform,
std::integer_sequence<long long, I...>) const
-> decltype(transform(
expr_tag<expr_kind::call>{},
terminal_value(::boost::yap::get(
static_cast<Expr &&>(expr), hana::llong_c<I>))...))
{
return transform(
expr_tag<expr_kind::call>{},
terminal_value(::boost::yap::get(
static_cast<Expr &&>(expr), hana::llong_c<I>))...);
}
};
template<typename Expr>
constexpr auto indices_for(Expr const & expr)
{
constexpr long long size = decltype(hana::size(expr.elements))::value;
return std::make_integer_sequence<long long, size>();
}
template<bool Strict, typename Expr, typename TransformTuple, int I>
struct transform_expression_tag<
Strict,
Expr,
TransformTuple,
I,
expr_arity::n,
void_t<decltype(
transform_call_unpacker<
Expr,
decltype(*std::declval<TransformTuple>()[hana::llong<I>{}])>{}(
std::declval<Expr>(),
*std::declval<TransformTuple>()[hana::llong<I>{}],
indices_for(std::declval<Expr>())))>>
{
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
using transform_t = decltype(*transforms[hana::llong<I>{}]);
return transform_call_unpacker<Expr, transform_t>{}(
static_cast<Expr &&>(expr),
*transforms[hana::llong<I>{}],
indices_for(expr));
}
};
template<bool Strict, int I, bool IsExprRef>
struct transform_impl
{
template<typename Expr, typename TransformTuple>
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
return detail::transform_expression_tag<
Strict,
Expr,
TransformTuple,
I,
detail::arity_of<kind>()>{}(
static_cast<Expr &&>(expr), transforms);
}
};
template<bool Strict, int I>
struct transform_impl<Strict, I, true>
{
template<typename Expr, typename TransformTuple>
constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
{
return detail::transform_impl<Strict, I, false>{}(
::boost::yap::deref(static_cast<Expr &&>(expr)), transforms);
}
};
}}}
#endif

View File

@@ -0,0 +1,338 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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_YAP_EXPRESSION_HPP_INCLUDED
#define BOOST_YAP_EXPRESSION_HPP_INCLUDED
#include <boost/yap/algorithm.hpp>
namespace boost { namespace yap {
/** Reference expression template that provides all operator overloads.
\note Due to a limitation of Doxygen, each of the
<code>value()</code>, <code>left()</code>, <code>right()</code>, and
operator overloads listed here is a stand-in for three member
functions. For each function <code>f</code>, the listing here is:
\code return_type f (); \endcode However, there are actually three
functions:
\code
return_type f () const &;
return_type f () &;
return_type f () &&;
\endcode
*/
template<expr_kind Kind, typename Tuple>
struct expression
{
using tuple_type = Tuple;
static const expr_kind kind = Kind;
/** Default constructor. Does nothing. */
constexpr expression() {}
/** Moves \a rhs into the only data mamber, \c elements. */
constexpr expression(tuple_type && rhs) :
elements(static_cast<tuple_type &&>(rhs))
{}
tuple_type elements;
/** A convenience member function that dispatches to the free function
<code>value()</code>. */
constexpr decltype(auto) value() &
{
return ::boost::yap::value(*this);
}
#ifndef BOOST_YAP_DOXYGEN
constexpr decltype(auto) value() const &
{
return ::boost::yap::value(*this);
}
constexpr decltype(auto) value() &&
{
return ::boost::yap::value(std::move(*this));
}
#endif
/** A convenience member function that dispatches to the free function
<code>left()</code>. */
constexpr decltype(auto) left() & { return ::boost::yap::left(*this); }
#ifndef BOOST_YAP_DOXYGEN
constexpr decltype(auto) left() const &
{
return ::boost::yap::left(*this);
}
constexpr decltype(auto) left() &&
{
return ::boost::yap::left(std::move(*this));
}
#endif
/** A convenience member function that dispatches to the free function
<code>right()</code>. */
constexpr decltype(auto) right() &
{
return ::boost::yap::right(*this);
}
#ifndef BOOST_YAP_DOXYGEN
constexpr decltype(auto) right() const &
{
return ::boost::yap::right(*this);
}
constexpr decltype(auto) right() &&
{
return ::boost::yap::right(std::move(*this));
}
#endif
BOOST_YAP_USER_ASSIGN_OPERATOR(
expression, ::boost::yap::expression) // =
BOOST_YAP_USER_SUBSCRIPT_OPERATOR(::boost::yap::expression) // []
BOOST_YAP_USER_CALL_OPERATOR(::boost::yap::expression) // ()
};
/** Terminal expression specialization of the reference expression
template.
\note Due to a limitation of Doxygen, the <code>value()</code> member
and each of the operator overloads listed here is a stand-in for three
member functions. For each function <code>f</code>, the listing here
is: \code return_type f (); \endcode However, there are actually three
functions:
\code
return_type f () const &;
return_type f () &;
return_type f () &&;
\endcode
*/
template<typename T>
struct expression<expr_kind::terminal, hana::tuple<T>>
{
using tuple_type = hana::tuple<T>;
static const expr_kind kind = expr_kind::terminal;
/** Default constructor. Does nothing. */
constexpr expression() {}
/** Forwards \a t into \c elements. */
constexpr expression(T && t) : elements(static_cast<T &&>(t)) {}
/** Copies \a rhs into the only data mamber, \c elements. */
constexpr expression(hana::tuple<T> const & rhs) : elements(rhs) {}
/** Moves \a rhs into the only data mamber, \c elements. */
constexpr expression(hana::tuple<T> && rhs) : elements(std::move(rhs))
{}
tuple_type elements;
/** A convenience member function that dispatches to the free function
<code>value()</code>. */
constexpr decltype(auto) value() &
{
return ::boost::yap::value(*this);
}
#ifndef BOOST_YAP_DOXYGEN
constexpr decltype(auto) value() const &
{
return ::boost::yap::value(*this);
}
constexpr decltype(auto) value() &&
{
return ::boost::yap::value(std::move(*this));
}
#endif
BOOST_YAP_USER_ASSIGN_OPERATOR(
expression, ::boost::yap::expression) // =
BOOST_YAP_USER_SUBSCRIPT_OPERATOR(::boost::yap::expression) // []
BOOST_YAP_USER_CALL_OPERATOR(::boost::yap::expression) // ()
};
#ifndef BOOST_YAP_DOXYGEN
BOOST_YAP_USER_UNARY_OPERATOR(unary_plus, expression, expression) // +
BOOST_YAP_USER_UNARY_OPERATOR(negate, expression, expression) // -
BOOST_YAP_USER_UNARY_OPERATOR(dereference, expression, expression) // *
BOOST_YAP_USER_UNARY_OPERATOR(complement, expression, expression) // ~
BOOST_YAP_USER_UNARY_OPERATOR(address_of, expression, expression) // &
BOOST_YAP_USER_UNARY_OPERATOR(logical_not, expression, expression) // !
BOOST_YAP_USER_UNARY_OPERATOR(pre_inc, expression, expression) // ++
BOOST_YAP_USER_UNARY_OPERATOR(pre_dec, expression, expression) // --
BOOST_YAP_USER_UNARY_OPERATOR(post_inc, expression, expression) // ++(int)
BOOST_YAP_USER_UNARY_OPERATOR(post_dec, expression, expression) // --(int)
BOOST_YAP_USER_BINARY_OPERATOR(shift_left, expression, expression) // <<
BOOST_YAP_USER_BINARY_OPERATOR(shift_right, expression, expression) // >>
BOOST_YAP_USER_BINARY_OPERATOR(multiplies, expression, expression) // *
BOOST_YAP_USER_BINARY_OPERATOR(divides, expression, expression) // /
BOOST_YAP_USER_BINARY_OPERATOR(modulus, expression, expression) // %
BOOST_YAP_USER_BINARY_OPERATOR(plus, expression, expression) // +
BOOST_YAP_USER_BINARY_OPERATOR(minus, expression, expression) // -
BOOST_YAP_USER_BINARY_OPERATOR(less, expression, expression) // <
BOOST_YAP_USER_BINARY_OPERATOR(greater, expression, expression) // >
BOOST_YAP_USER_BINARY_OPERATOR(less_equal, expression, expression) // <=
BOOST_YAP_USER_BINARY_OPERATOR(greater_equal, expression, expression) // >=
BOOST_YAP_USER_BINARY_OPERATOR(equal_to, expression, expression) // ==
BOOST_YAP_USER_BINARY_OPERATOR(not_equal_to, expression, expression) // !=
BOOST_YAP_USER_BINARY_OPERATOR(logical_or, expression, expression) // ||
BOOST_YAP_USER_BINARY_OPERATOR(logical_and, expression, expression) // &&
BOOST_YAP_USER_BINARY_OPERATOR(bitwise_and, expression, expression) // &
BOOST_YAP_USER_BINARY_OPERATOR(bitwise_or, expression, expression) // |
BOOST_YAP_USER_BINARY_OPERATOR(bitwise_xor, expression, expression) // ^
BOOST_YAP_USER_BINARY_OPERATOR(comma, expression, expression) // ,
BOOST_YAP_USER_BINARY_OPERATOR(mem_ptr, expression, expression) // ->*
BOOST_YAP_USER_BINARY_OPERATOR(shift_left_assign, expression, expression) // <<=
BOOST_YAP_USER_BINARY_OPERATOR(shift_right_assign, expression, expression) // >>=
BOOST_YAP_USER_BINARY_OPERATOR(multiplies_assign, expression, expression) // *=
BOOST_YAP_USER_BINARY_OPERATOR(divides_assign, expression, expression) // /=
BOOST_YAP_USER_BINARY_OPERATOR(modulus_assign, expression, expression) // %=
BOOST_YAP_USER_BINARY_OPERATOR(plus_assign, expression, expression) // +=
BOOST_YAP_USER_BINARY_OPERATOR(minus_assign, expression, expression) // -=
BOOST_YAP_USER_BINARY_OPERATOR(bitwise_and_assign, expression, expression) // &=
BOOST_YAP_USER_BINARY_OPERATOR(bitwise_or_assign, expression, expression) // |=
BOOST_YAP_USER_BINARY_OPERATOR(bitwise_xor_assign, expression, expression) // ^=
BOOST_YAP_USER_EXPR_IF_ELSE(expression)
#else
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator+(Expr &&);
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator-(Expr &&);
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator*(Expr &&);
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator~(Expr &&);
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator&(Expr &&);
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator!(Expr &&);
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator++(Expr &&);
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator--(Expr &&);
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator++(Expr &&, int);
/** \see BOOST_YAP_USER_UNARY_OPERATOR for full semantics. */
template<typename Expr>
constexpr auto operator--(Expr &&, int);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator<<(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator>>(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator*(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator/(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator%(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator+(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator-(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator<(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator>(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator<=(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator>=(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator==(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator!=(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator||(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator&&(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator&(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator|(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_BINARY_OPERATOR for full semantics. */
template<typename LExpr, typename RExpr>
constexpr auto operator^(LExpr && lhs, RExpr && rhs);
/** \see BOOST_YAP_USER_EXPR_IF_ELSE for full semantics. */
template<typename Expr1, typename Expr2, typename Expr3>
constexpr auto if_else(Expr1 && expr1, Expr2 && expr2, Expr3 && expr3);
#endif
/** Returns <code>make_expression<boost::yap::expression, Kind>(...)</code>.
*/
template<expr_kind Kind, typename... T>
constexpr auto make_expression(T &&... t)
{
return make_expression<expression, Kind>(static_cast<T &&>(t)...);
}
/** Returns <code>make_terminal<boost::yap::expression>(t)</code>. */
template<typename T>
constexpr auto make_terminal(T && t)
{
return make_terminal<expression>(static_cast<T &&>(t));
}
/** Returns <code>as_expr<boost::yap::expression>(t)</code>. */
template<typename T>
constexpr decltype(auto) as_expr(T && t)
{
return as_expr<expression>(static_cast<T &&>(t));
}
}}
#endif

View File

@@ -0,0 +1,320 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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_YAP_PRINT_HPP_INCLUDED
#define BOOST_YAP_PRINT_HPP_INCLUDED
#include <boost/yap/algorithm_fwd.hpp>
#include <boost/hana/for_each.hpp>
#include <boost/type_index.hpp>
#include <iostream>
namespace boost { namespace yap {
/** Returns the <code>char const *</code> string for the spelling of the
C++ operator associated with \a kind. It returns the special values
"ref" and "term" for the non-operator kinds
<code>expr_kind::expr_ref</code> amd <code>expr_kind::terminal</code>,
respectively.*/
inline constexpr char const * op_string(expr_kind kind)
{
switch (kind) {
case expr_kind::expr_ref: return "ref";
case expr_kind::terminal: return "term";
case expr_kind::unary_plus: return "+";
case expr_kind::negate: return "-";
case expr_kind::dereference: return "*";
case expr_kind::complement: return "~";
case expr_kind::address_of: return "&";
case expr_kind::logical_not: return "!";
case expr_kind::pre_inc: return "++";
case expr_kind::pre_dec: return "--";
case expr_kind::post_inc: return "++(int)";
case expr_kind::post_dec: return "--(int)";
case expr_kind::shift_left: return "<<";
case expr_kind::shift_right: return ">>";
case expr_kind::multiplies: return "*";
case expr_kind::divides: return "/";
case expr_kind::modulus: return "%";
case expr_kind::plus: return "+";
case expr_kind::minus: return "-";
case expr_kind::less: return "<";
case expr_kind::greater: return ">";
case expr_kind::less_equal: return "<=";
case expr_kind::greater_equal: return ">=";
case expr_kind::equal_to: return "==";
case expr_kind::not_equal_to: return "!=";
case expr_kind::logical_or: return "||";
case expr_kind::logical_and: return "&&";
case expr_kind::bitwise_and: return "&";
case expr_kind::bitwise_or: return "|";
case expr_kind::bitwise_xor: return "^";
case expr_kind::comma: return ",";
case expr_kind::mem_ptr: return "->*";
case expr_kind::assign: return "=";
case expr_kind::shift_left_assign: return "<<=";
case expr_kind::shift_right_assign: return ">>=";
case expr_kind::multiplies_assign: return "*=";
case expr_kind::divides_assign: return "/=";
case expr_kind::modulus_assign: return "%=";
case expr_kind::plus_assign: return "+=";
case expr_kind::minus_assign: return "-=";
case expr_kind::bitwise_and_assign: return "&=";
case expr_kind::bitwise_or_assign: return "|=";
case expr_kind::bitwise_xor_assign: return "^=";
case expr_kind::subscript: return "[]";
case expr_kind::if_else: return "?:";
case expr_kind::call: return "()";
default: return "** ERROR: UNKNOWN OPERATOR! **";
}
}
namespace detail {
inline std::ostream & print_kind(std::ostream & os, expr_kind kind)
{
return os << op_string(kind);
}
template<typename T, typename = void_t<>>
struct printer
{
std::ostream & operator()(std::ostream & os, T const &)
{
return os << "<<unprintable-value>>";
}
};
template<typename T>
struct printer<
T,
void_t<decltype(
std::declval<std::ostream &>() << std::declval<T const &>())>>
{
std::ostream & operator()(std::ostream & os, T const & x)
{
return os << x;
}
};
template<typename T>
inline std::ostream & print_value(std::ostream & os, T const & x)
{
return printer<T>{}(os, x);
}
template<long long I>
inline std::ostream & print_value(std::ostream & os, hana::llong<I>)
{
return os << I << "_p";
}
template<typename T>
std::ostream & print_type(std::ostream & os, hana::tuple<T> const &)
{
os << typeindex::type_id<T>().pretty_name();
if (std::is_const<std::remove_reference_t<T>>::value)
os << " const";
if (std::is_volatile<std::remove_reference_t<T>>::value)
os << " volatile";
if (std::is_lvalue_reference<T>::value)
os << " &";
if (std::is_rvalue_reference<T>::value)
os << " &&";
return os;
}
template<typename T>
bool is_const_expr_ref(T const &)
{
return false;
}
template<typename T, template<expr_kind, class> class expr_template>
bool is_const_expr_ref(
expr_template<expr_kind::expr_ref, hana::tuple<T const *>> const &)
{
return true;
}
#ifdef BOOST_NO_CONSTEXPR_IF
template<expr_kind Kind>
struct print_impl
{
template<typename Expr>
std::ostream & operator()(
std::ostream & os,
Expr const & expr,
int indent,
char const * indent_str,
bool is_ref = false,
bool is_const_ref = false)
{
for (int i = 0; i < indent; ++i) {
os << indent_str;
}
os << "expr<";
::boost::yap::detail::print_kind(os, Expr::kind);
os << ">";
if (is_const_ref)
os << " const &";
else if (is_ref)
os << " &";
os << "\n";
hana::for_each(
expr.elements,
[&os, indent, indent_str](auto const & element) {
using element_type = decltype(element);
constexpr expr_kind kind =
detail::remove_cv_ref_t<element_type>::kind;
print_impl<kind>{}(os, element, indent + 1, indent_str);
});
return os;
}
};
template<>
struct print_impl<expr_kind::expr_ref>
{
template<typename Expr>
std::ostream & operator()(
std::ostream & os,
Expr const & expr,
int indent,
char const * indent_str,
bool is_ref = false,
bool is_const_ref = false)
{
using ref_type = decltype(::boost::yap::deref(expr));
constexpr expr_kind ref_kind =
detail::remove_cv_ref_t<ref_type>::kind;
print_impl<ref_kind>{}(
os,
::boost::yap::deref(expr),
indent,
indent_str,
true,
::boost::yap::detail::is_const_expr_ref(expr));
return os;
}
};
template<>
struct print_impl<expr_kind::terminal>
{
template<typename Expr>
std::ostream & operator()(
std::ostream & os,
Expr const & expr,
int indent,
char const * indent_str,
bool is_ref = false,
bool is_const_ref = false)
{
for (int i = 0; i < indent; ++i) {
os << indent_str;
}
os << "term<";
::boost::yap::detail::print_type(os, expr.elements);
os << ">[=";
::boost::yap::detail::print_value(
os, ::boost::yap::value(expr));
os << "]";
if (is_const_ref)
os << " const &";
else if (is_ref)
os << " &";
os << "\n";
return os;
}
};
#else
template<typename Expr>
std::ostream & print_impl(
std::ostream & os,
Expr const & expr,
int indent,
char const * indent_str,
bool is_ref = false,
bool is_const_ref = false)
{
if constexpr (Expr::kind == expr_kind::expr_ref) {
print_impl(
os,
::boost::yap::deref(expr),
indent,
indent_str,
true,
::boost::yap::detail::is_const_expr_ref(expr));
} else {
for (int i = 0; i < indent; ++i) {
os << indent_str;
}
if constexpr (Expr::kind == expr_kind::terminal) {
os << "term<";
::boost::yap::detail::print_type(os, expr.elements);
os << ">[=";
::boost::yap::detail::print_value(
os, ::boost::yap::value(expr));
os << "]";
if (is_const_ref)
os << " const &";
else if (is_ref)
os << " &";
os << "\n";
} else {
os << "expr<";
::boost::yap::detail::print_kind(os, Expr::kind);
os << ">";
if (is_const_ref)
os << " const &";
else if (is_ref)
os << " &";
os << "\n";
hana::for_each(
expr.elements,
[&os, indent, indent_str](auto const & element) {
::boost::yap::detail::print_impl(
os, element, indent + 1, indent_str);
});
}
}
return os;
}
#endif // BOOST_NO_CONSTEXPR_IF
}
/** Prints expression \a expr to stream \a os. Returns \a os. */
template<typename Expr>
std::ostream & print(std::ostream & os, Expr const & expr)
{
#ifdef BOOST_NO_CONSTEXPR_IF
return detail::print_impl<detail::remove_cv_ref_t<Expr>::kind>{}(
os, expr, 0, " ");
#else
return detail::print_impl(os, expr, 0, " ");
#endif
}
}}
#endif

View File

@@ -0,0 +1,829 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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_YAP_USER_MACROS_HPP_INCLUDED
#define BOOST_YAP_USER_MACROS_HPP_INCLUDED
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#ifndef BOOST_YAP_DOXYGEN
// unary
#define BOOST_YAP_OPERATOR_unary_plus(...) +(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_negate(...) -(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_dereference(...) *(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_complement(...) ~(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_address_of(...) &(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_logical_not(...) !(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_pre_inc(...) ++(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_pre_dec(...) --(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_post_inc(...) ++(__VA_ARGS__, int)
#define BOOST_YAP_OPERATOR_post_dec(...) --(__VA_ARGS__, int)
// binary
#define BOOST_YAP_OPERATOR_shift_left(...) <<(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_shift_right(...) >>(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_multiplies(...) *(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_divides(...) /(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_modulus(...) %(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_plus(...) +(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_minus(...) -(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_less(...) <(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_greater(...) >(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_less_equal(...) <=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_greater_equal(...) >=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_equal_to(...) ==(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_not_equal_to(...) !=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_logical_or(...) ||(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_logical_and(...) &&(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_bitwise_and(...) &(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_bitwise_or(...) |(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_bitwise_xor(...) ^(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_comma(...) ,(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_mem_ptr(...) ->*(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_assign(...) =(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_shift_left_assign(...) <<=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_shift_right_assign(...) >>=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_multiplies_assign(...) *=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_divides_assign(...) /=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_modulus_assign(...) %=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_plus_assign(...) +=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_minus_assign(...) -=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_bitwise_and_assign(...) &=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_bitwise_or_assign(...) |=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_bitwise_xor_assign(...) ^=(__VA_ARGS__)
#define BOOST_YAP_OPERATOR_subscript(...) [](__VA_ARGS__)
#define BOOST_YAP_INDIRECT_CALL(macro) BOOST_PP_CAT(BOOST_YAP_OPERATOR_, macro)
#endif // BOOST_YAP_DOXYGEN
/** Defines operator overloads for unary operator \a op_name that each take an
expression instantiated from \a expr_template and return an expression
instantiated from the \a result_expr_template expression template. One
overload is defined for each of the qualifiers <code>const &</code>,
<code>&</code>, and <code>&&</code>. For the lvalue reference overloads,
the argument is captured by reference into the resulting expression. For
the rvalue reference overload, the argument is moved into the resulting
expression.
Example:
\snippet user_macros_snippets.cpp USER_UNARY_OPERATOR
\param op_name The operator to be overloaded; this must be one of the \b
unary enumerators in <code>expr_kind</code>, without the
<code>expr_kind::</code> qualification.
\param expr_template The expression template to which the overloads apply.
\a expr_template must be an \ref ExpressionTemplate.
\param result_expr_template The expression template to use to instantiate
the result expression. \a result_expr_template must be an \ref
ExpressionTemplate.
*/
#define BOOST_YAP_USER_UNARY_OPERATOR( \
op_name, expr_template, result_expr_template) \
template<::boost::yap::expr_kind Kind, typename Tuple> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)( \
expr_template<Kind, Tuple> const & x) \
{ \
using lhs_type = ::boost::yap::detail::operand_type_t< \
result_expr_template, \
expr_template<Kind, Tuple> const &>; \
using tuple_type = ::boost::hana::tuple<lhs_type>; \
return result_expr_template< \
::boost::yap::expr_kind::op_name, \
tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(x)}}; \
} \
template<::boost::yap::expr_kind Kind, typename Tuple> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)( \
expr_template<Kind, Tuple> & x) \
{ \
using lhs_type = ::boost::yap::detail::operand_type_t< \
result_expr_template, \
expr_template<Kind, Tuple> &>; \
using tuple_type = ::boost::hana::tuple<lhs_type>; \
return result_expr_template< \
::boost::yap::expr_kind::op_name, \
tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(x)}}; \
} \
template<::boost::yap::expr_kind Kind, typename Tuple> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)( \
expr_template<Kind, Tuple> && x) \
{ \
using tuple_type = ::boost::hana::tuple<expr_template<Kind, Tuple>>; \
return result_expr_template< \
::boost::yap::expr_kind::op_name, \
tuple_type>{tuple_type{std::move(x)}}; \
}
/** Defines operator overloads for binary operator \a op_name that each
produce an expression instantiated from the \a expr_template expression
template. One overload is defined for each of the qualifiers <code>const
&</code>, <code>&</code>, and <code>&&</code>. For the lvalue reference
overloads, <code>*this</code> is captured by reference into the resulting
expression. For the rvalue reference overload, <code>*this</code> is
moved into the resulting expression.
Note that this does not work for yap::expr_kinds assign, subscript, or
call. Use BOOST_YAP_USER_ASSIGN_OPERATOR,
BOOST_YAP_USER_SUBSCRIPT_OPERATOR, or BOOST_YAP_USER_CALL_OPERATOR for
those, respectively.
Example:
\snippet user_macros_snippets.cpp USER_BINARY_OPERATOR
\param op_name The operator to be overloaded; this must be one of the \b
binary enumerators in <code>expr_kind</code>, except assign, subscript, or
call, without the <code>expr_kind::</code> qualification.
\param expr_template The expression template to which the overloads apply.
\a expr_template must be an \ref ExpressionTemplate.
\param result_expr_template The expression template to use to instantiate
the result expression. \a result_expr_template must be an \ref
ExpressionTemplate.
*/
#define BOOST_YAP_USER_BINARY_OPERATOR( \
op_name, expr_template, result_expr_template) \
template<::boost::yap::expr_kind Kind, typename Tuple, typename Expr> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)( \
expr_template<Kind, Tuple> const & lhs, Expr && rhs) \
{ \
using lhs_type = ::boost::yap::detail::operand_type_t< \
result_expr_template, \
expr_template<Kind, Tuple> const &>; \
using rhs_type = \
::boost::yap::detail::operand_type_t<result_expr_template, Expr>; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return result_expr_template< \
::boost::yap::expr_kind::op_name, \
tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(lhs), \
::boost::yap::detail::make_operand<rhs_type>{}( \
static_cast<Expr &&>(rhs))}}; \
} \
template<::boost::yap::expr_kind Kind, typename Tuple, typename Expr> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)( \
expr_template<Kind, Tuple> & lhs, Expr && rhs) \
{ \
using lhs_type = ::boost::yap::detail::operand_type_t< \
result_expr_template, \
expr_template<Kind, Tuple> &>; \
using rhs_type = \
::boost::yap::detail::operand_type_t<result_expr_template, Expr>; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return result_expr_template< \
::boost::yap::expr_kind::op_name, \
tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(lhs), \
::boost::yap::detail::make_operand<rhs_type>{}( \
static_cast<Expr &&>(rhs))}}; \
} \
template<::boost::yap::expr_kind Kind, typename Tuple, typename Expr> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)( \
expr_template<Kind, Tuple> && lhs, Expr && rhs) \
{ \
using lhs_type = ::boost::yap::detail::remove_cv_ref_t< \
expr_template<Kind, Tuple> &&>; \
using rhs_type = \
::boost::yap::detail::operand_type_t<result_expr_template, Expr>; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return result_expr_template< \
::boost::yap::expr_kind::op_name, \
tuple_type>{ \
tuple_type{std::move(lhs), \
::boost::yap::detail::make_operand<rhs_type>{}( \
static_cast<Expr &&>(rhs))}}; \
} \
template<typename T, ::boost::yap::expr_kind Kind, typename Tuple> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)( \
T && lhs, expr_template<Kind, Tuple> && rhs) \
->::boost::yap::detail::free_binary_op_result_t< \
result_expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
expr_template<Kind, Tuple> &&> \
{ \
using result_types = ::boost::yap::detail::free_binary_op_result< \
result_expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
expr_template<Kind, Tuple> &&>; \
using lhs_type = typename result_types::lhs_type; \
using rhs_type = typename result_types::rhs_type; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return {tuple_type{lhs_type{static_cast<T &&>(lhs)}, std::move(rhs)}}; \
} \
template<typename T, ::boost::yap::expr_kind Kind, typename Tuple> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)( \
T && lhs, expr_template<Kind, Tuple> const & rhs) \
->::boost::yap::detail::free_binary_op_result_t< \
result_expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
expr_template<Kind, Tuple> const &> \
{ \
using result_types = ::boost::yap::detail::free_binary_op_result< \
result_expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
expr_template<Kind, Tuple> const &>; \
using lhs_type = typename result_types::lhs_type; \
using rhs_type = typename result_types::rhs_type; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
using rhs_tuple_type = typename result_types::rhs_tuple_type; \
return {tuple_type{lhs_type{static_cast<T &&>(lhs)}, \
rhs_type{rhs_tuple_type{std::addressof(rhs)}}}}; \
} \
template<typename T, ::boost::yap::expr_kind Kind, typename Tuple> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)( \
T && lhs, expr_template<Kind, Tuple> & rhs) \
->::boost::yap::detail::free_binary_op_result_t< \
result_expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
expr_template<Kind, Tuple> &> \
{ \
using result_types = ::boost::yap::detail::free_binary_op_result< \
result_expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
expr_template<Kind, Tuple> &>; \
using lhs_type = typename result_types::lhs_type; \
using rhs_type = typename result_types::rhs_type; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
using rhs_tuple_type = typename result_types::rhs_tuple_type; \
return {tuple_type{lhs_type{static_cast<T &&>(lhs)}, \
rhs_type{rhs_tuple_type{std::addressof(rhs)}}}}; \
}
/** Defines operator overloads for \a operator=() that each produce an
expression instantiated from the \a expr_template expression template.
One overload is defined for each of the qualifiers <code>const &</code>,
<code>&</code>, and <code>&&</code>. For the lvalue reference overloads,
<code>*this</code> is captured by reference into the resulting expression.
For the rvalue reference overload, <code>*this</code> is moved into the
resulting expression.
The \a rhs parameter to each of the defined overloads may be any type,
including an expression, except that the overloads are constrained by
std::enable_if<> not to conflict with the assignment and move assignement
operators. If \a rhs is a non-expression, it is wrapped in a terminal
expression.
Example:
\snippet user_macros_snippets.cpp USER_ASSIGN_OPERATOR
\param this_type The type of the class the operator is a member of; this
is required to avoid clashing with the assignment and move assignement
operators.
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
*/
#define BOOST_YAP_USER_ASSIGN_OPERATOR(this_type, expr_template) \
template< \
typename Expr, \
typename = std::enable_if_t< \
!::boost::yap::detail::copy_or_move<this_type, Expr &&>::value>> \
constexpr auto operator=(Expr && rhs) const & \
{ \
using lhs_type = ::boost::yap::detail:: \
operand_type_t<expr_template, this_type const &>; \
using rhs_type = \
::boost::yap::detail::operand_type_t<expr_template, Expr>; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return expr_template<::boost::yap::expr_kind::assign, tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this), \
::boost::yap::detail::make_operand<rhs_type>{}( \
static_cast<Expr &&>(rhs))}}; \
} \
template< \
typename Expr, \
typename = std::enable_if_t< \
!::boost::yap::detail::copy_or_move<this_type, Expr &&>::value>> \
constexpr auto operator=(Expr && rhs) & \
{ \
using lhs_type = ::boost::yap::detail:: \
operand_type_t<expr_template, decltype(*this)>; \
using rhs_type = \
::boost::yap::detail::operand_type_t<expr_template, Expr>; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return expr_template<::boost::yap::expr_kind::assign, tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this), \
::boost::yap::detail::make_operand<rhs_type>{}( \
static_cast<Expr &&>(rhs))}}; \
} \
template< \
typename Expr, \
typename = std::enable_if_t< \
!::boost::yap::detail::copy_or_move<this_type, Expr &&>::value>> \
constexpr auto operator=(Expr && rhs) && \
{ \
using rhs_type = \
::boost::yap::detail::operand_type_t<expr_template, Expr>; \
using tuple_type = ::boost::hana::tuple<this_type, rhs_type>; \
return expr_template<::boost::yap::expr_kind::assign, tuple_type>{ \
tuple_type{std::move(*this), \
::boost::yap::detail::make_operand<rhs_type>{}( \
static_cast<Expr &&>(rhs))}}; \
}
/** Defines operator overloads for \a operator[]() that each produce an
expression instantiated from the \a expr_template expression template.
One overload is defined for each of the qualifiers <code>const &</code>,
<code>&</code>, and <code>&&</code>. For the lvalue reference overloads,
<code>*this</code> is captured by reference into the resulting expression.
For the rvalue reference overload, <code>*this</code> is moved into the
resulting expression.
The \a rhs parameter to each of the defined overloads may be any type,
including an expression, except that the overloads are constrained by
std::enable_if<> not to conflict with the assignment and move assignement
operators. If \a rhs is a non-expression, it is wrapped in a terminal
expression.
Example:
\snippet user_macros_snippets.cpp USER_SUBSCRIPT_OPERATOR
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
*/
#define BOOST_YAP_USER_SUBSCRIPT_OPERATOR(expr_template) \
template<typename Expr> \
constexpr auto operator[](Expr && rhs) const & \
{ \
using lhs_type = ::boost::yap::detail:: \
operand_type_t<expr_template, decltype(*this)>; \
using rhs_type = \
::boost::yap::detail::operand_type_t<expr_template, Expr>; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return expr_template<::boost::yap::expr_kind::subscript, tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this), \
::boost::yap::detail::make_operand<rhs_type>{}( \
static_cast<Expr &&>(rhs))}}; \
} \
template<typename Expr> \
constexpr auto operator[](Expr && rhs) & \
{ \
using lhs_type = ::boost::yap::detail:: \
operand_type_t<expr_template, decltype(*this)>; \
using rhs_type = \
::boost::yap::detail::operand_type_t<expr_template, Expr>; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return expr_template<::boost::yap::expr_kind::subscript, tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this), \
::boost::yap::detail::make_operand<rhs_type>{}( \
static_cast<Expr &&>(rhs))}}; \
} \
template<typename Expr> \
constexpr auto operator[](Expr && rhs) && \
{ \
using lhs_type = \
::boost::yap::detail::remove_cv_ref_t<decltype(*this)>; \
using rhs_type = \
::boost::yap::detail::operand_type_t<expr_template, Expr>; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return expr_template<::boost::yap::expr_kind::subscript, tuple_type>{ \
tuple_type{std::move(*this), \
::boost::yap::detail::make_operand<rhs_type>{}( \
static_cast<Expr &&>(rhs))}}; \
}
/** Defines operator overloads for the call operator taking any number of
parameters ("operator()") that each produce an expression instantiated
from the \a expr_template expression template. One overload is defined
for each of the qualifiers <code>const &</code>, <code>&</code>, and
<code>&&</code>. For the lvalue reference overloads, <code>*this</code>
is captured by reference into the resulting expression. For the rvalue
reference overload, <code>*this</code> is moved into the resulting
expression.
The \a u parameters to each of the defined overloads may be any type,
including an expression. Each non-expression is wrapped in a terminal
expression.
Example:
\snippet user_macros_snippets.cpp USER_CALL_OPERATOR
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
*/
#define BOOST_YAP_USER_CALL_OPERATOR(expr_template) \
template<typename... U> \
constexpr auto operator()(U &&... u) const & \
{ \
using lhs_type = ::boost::yap::detail:: \
operand_type_t<expr_template, decltype(*this)>; \
using tuple_type = ::boost::hana::tuple< \
lhs_type, \
::boost::yap::detail::operand_type_t<expr_template, U>...>; \
return expr_template<::boost::yap::expr_kind::call, tuple_type>{ \
tuple_type{ \
::boost::yap::detail::make_operand<lhs_type>{}(*this), \
::boost::yap::detail::make_operand< \
::boost::yap::detail::operand_type_t<expr_template, U>>{}( \
static_cast<U &&>(u))...}}; \
} \
template<typename... U> \
constexpr auto operator()(U &&... u) & \
{ \
using lhs_type = ::boost::yap::detail:: \
operand_type_t<expr_template, decltype(*this)>; \
using tuple_type = ::boost::hana::tuple< \
lhs_type, \
::boost::yap::detail::operand_type_t<expr_template, U>...>; \
return expr_template<::boost::yap::expr_kind::call, tuple_type>{ \
tuple_type{ \
::boost::yap::detail::make_operand<lhs_type>{}(*this), \
::boost::yap::detail::make_operand< \
::boost::yap::detail::operand_type_t<expr_template, U>>{}( \
static_cast<U &&>(u))...}}; \
} \
template<typename... U> \
constexpr auto operator()(U &&... u) && \
{ \
using this_type = \
::boost::yap::detail::remove_cv_ref_t<decltype(*this)>; \
using tuple_type = ::boost::hana::tuple< \
this_type, \
::boost::yap::detail::operand_type_t<expr_template, U>...>; \
return expr_template<::boost::yap::expr_kind::call, tuple_type>{ \
tuple_type{ \
std::move(*this), \
::boost::yap::detail::make_operand< \
::boost::yap::detail::operand_type_t<expr_template, U>>{}( \
static_cast<U &&>(u))...}}; \
}
#ifndef BOOST_YAP_DOXYGEN
#define BOOST_YAP_USER_CALL_OPERATOR_OPERAND_T(z, n, expr_template) \
::boost::yap::detail::operand_type_t<expr_template, BOOST_PP_CAT(U, n)>
#define BOOST_YAP_USER_CALL_OPERATOR_MAKE_OPERAND(z, n, expr_template) \
::boost::yap::detail::make_operand<::boost::yap::detail::operand_type_t< \
expr_template, \
BOOST_PP_CAT(U, n)>>{}( \
static_cast<BOOST_PP_CAT(U, n) &&>(BOOST_PP_CAT(u, n)))
#endif
/** Defines operator overloads for the call operator taking N parameters
("operator()(t0, t1, ... tn-1)") that each produce an expression
instantiated from the \a expr_template expression template. One overload
is defined for each of the qualifiers <code>const &</code>,
<code>&</code>, and <code>&&</code>. For the lvalue reference overloads,
<code>*this</code> is captured by reference into the resulting expression.
For the rvalue reference overload, <code>*this</code> is moved into the
resulting expression.
The \a u parameters to each of the defined overloads may be any type,
including an expression. Each non-expression is wrapped in a terminal
expression.
Example:
\snippet user_macros_snippets.cpp USER_CALL_OPERATOR
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
\param n The number of parameters accepted by the operator() overloads. n
must be <= BOOST_PP_LIMIT_REPEAT.
*/
#define BOOST_YAP_USER_CALL_OPERATOR_N(expr_template, n) \
template<BOOST_PP_ENUM_PARAMS(n, typename U)> \
constexpr auto operator()(BOOST_PP_ENUM_BINARY_PARAMS(n, U, &&u)) const & \
{ \
using lhs_type = ::boost::yap::detail:: \
operand_type_t<expr_template, decltype(*this)>; \
using tuple_type = ::boost::hana::tuple< \
lhs_type, \
BOOST_PP_ENUM( \
n, BOOST_YAP_USER_CALL_OPERATOR_OPERAND_T, expr_template)>; \
return expr_template<::boost::yap::expr_kind::call, tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this), \
BOOST_PP_ENUM( \
n, \
BOOST_YAP_USER_CALL_OPERATOR_MAKE_OPERAND, \
expr_template)}}; \
} \
template<BOOST_PP_ENUM_PARAMS(n, typename U)> \
constexpr auto operator()(BOOST_PP_ENUM_BINARY_PARAMS(n, U, &&u)) & \
{ \
using lhs_type = ::boost::yap::detail:: \
operand_type_t<expr_template, decltype(*this)>; \
using tuple_type = ::boost::hana::tuple< \
lhs_type, \
BOOST_PP_ENUM( \
n, BOOST_YAP_USER_CALL_OPERATOR_OPERAND_T, expr_template)>; \
return expr_template<::boost::yap::expr_kind::call, tuple_type>{ \
tuple_type{::boost::yap::detail::make_operand<lhs_type>{}(*this), \
BOOST_PP_ENUM( \
n, \
BOOST_YAP_USER_CALL_OPERATOR_MAKE_OPERAND, \
expr_template)}}; \
} \
template<BOOST_PP_ENUM_PARAMS(n, typename U)> \
constexpr auto operator()(BOOST_PP_ENUM_BINARY_PARAMS(n, U, &&u)) && \
{ \
using this_type = \
::boost::yap::detail::remove_cv_ref_t<decltype(*this)>; \
using tuple_type = ::boost::hana::tuple< \
this_type, \
BOOST_PP_ENUM( \
n, BOOST_YAP_USER_CALL_OPERATOR_OPERAND_T, expr_template)>; \
return expr_template<::boost::yap::expr_kind::call, tuple_type>{ \
tuple_type{std::move(*this), \
BOOST_PP_ENUM( \
n, \
BOOST_YAP_USER_CALL_OPERATOR_MAKE_OPERAND, \
expr_template)}}; \
}
/** Defines a 3-parameter function <code>if_else()</code> that acts as an
analogue to the ternary operator (<code>?:</code>), since the ternary
operator is not user-overloadable. The return type of
<code>if_else()</code> is an expression instantiated from the \a
expr_template expression template.
At least one parameter to <code>if_else()</code> must be an expression.
For each parameter E passed to <code>if_else()</code>, if E is an rvalue,
E is moved into the result, and otherwise E is captured by reference into
the result.
Example:
\snippet user_macros_snippets.cpp USER_EXPR_IF_ELSE
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
*/
#define BOOST_YAP_USER_EXPR_IF_ELSE(expr_template) \
template<typename Expr1, typename Expr2, typename Expr3> \
constexpr auto if_else(Expr1 && expr1, Expr2 && expr2, Expr3 && expr3) \
->::boost::yap::detail:: \
ternary_op_result_t<expr_template, Expr1, Expr2, Expr3> \
{ \
using result_types = ::boost::yap::detail:: \
ternary_op_result<expr_template, Expr1, Expr2, Expr3>; \
using cond_type = typename result_types::cond_type; \
using then_type = typename result_types::then_type; \
using else_type = typename result_types::else_type; \
using tuple_type = \
::boost::hana::tuple<cond_type, then_type, else_type>; \
return {tuple_type{::boost::yap::detail::make_operand<cond_type>{}( \
static_cast<Expr1 &&>(expr1)), \
::boost::yap::detail::make_operand<then_type>{}( \
static_cast<Expr2 &&>(expr2)), \
::boost::yap::detail::make_operand<else_type>{}( \
static_cast<Expr3 &&>(expr3))}}; \
}
/** Defines a function <code>if_else()</code> that acts as an analogue to the
ternary operator (<code>?:</code>), since the ternary operator is not
user-overloadable. The return type of <code>if_else()</code> is an
expression instantiated from the \a expr_template expression template.
Each parameter to <code>if_else()</code> may be any type that is \b not an
expression. At least on parameter must be a type <code>T</code> for which
\code udt_trait<std::remove_cv_t<std::remove_reference_t<T>>>::value
\endcode is true. Each parameter is wrapped in a terminal expression.
Example:
\snippet user_macros_snippets.cpp USER_UDT_ANY_IF_ELSE
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
\param udt_trait A trait template to use to constrain which types are
accepted as template parameters to <code>if_else()</code>.
*/
#define BOOST_YAP_USER_UDT_ANY_IF_ELSE(expr_template, udt_trait) \
template<typename Expr1, typename Expr2, typename Expr3> \
constexpr auto if_else(Expr1 && expr1, Expr2 && expr2, Expr3 && expr3) \
->::boost::yap::detail::udt_any_ternary_op_result_t< \
expr_template, \
Expr1, \
Expr2, \
Expr3, \
udt_trait> \
{ \
using result_types = ::boost::yap::detail::udt_any_ternary_op_result< \
expr_template, \
Expr1, \
Expr2, \
Expr3, \
udt_trait>; \
using cond_type = typename result_types::cond_type; \
using then_type = typename result_types::then_type; \
using else_type = typename result_types::else_type; \
using tuple_type = \
::boost::hana::tuple<cond_type, then_type, else_type>; \
return {tuple_type{::boost::yap::detail::make_operand<cond_type>{}( \
static_cast<Expr1 &&>(expr1)), \
::boost::yap::detail::make_operand<then_type>{}( \
static_cast<Expr2 &&>(expr2)), \
::boost::yap::detail::make_operand<else_type>{}( \
static_cast<Expr3 &&>(expr3))}}; \
}
/** Defines a free/non-member operator overload for unary operator \a op_name
that produces an expression instantiated from the \a expr_template
expression template.
The parameter to the defined operator overload may be any type that is \b
not an expression and for which \code
udt_trait<std::remove_cv_t<std::remove_reference_t<T>>>::value \endcode is
true. The parameter is wrapped in a terminal expression.
Example:
\snippet user_macros_snippets.cpp USER_UDT_UNARY_OPERATOR
\param op_name The operator to be overloaded; this must be one of the \b
unary enumerators in <code>expr_kind</code>, without the
<code>expr_kind::</code> qualification.
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
\param udt_trait A trait template to use to constrain which types are
accepted as template parameters to the defined operator overload.
*/
#define BOOST_YAP_USER_UDT_UNARY_OPERATOR(op_name, expr_template, udt_trait) \
template<typename T> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(T && x) \
->::boost::yap::detail::udt_unary_op_result_t< \
expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
udt_trait> \
{ \
using result_types = ::boost::yap::detail::udt_unary_op_result< \
expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
udt_trait>; \
using x_type = typename result_types::x_type; \
using tuple_type = ::boost::hana::tuple<x_type>; \
return {tuple_type{x_type{static_cast<T &&>(x)}}}; \
}
/** Defines a free/non-member operator overload for binary operator \a op_name
that produces an expression instantiated from the \a expr_template
expression template.
The \a lhs parameter to the defined operator overload may be any type that
is \b not an expression and for which \code
t_udt_trait<std::remove_cv_t<std::remove_reference_t<T>>>::value \endcode is
true. The parameter is wrapped in a terminal expression.
The \a rhs parameter to the defined operator overload may be any type that
is \b not an expression and for which \code
u_udt_trait<std::remove_cv_t<std::remove_reference_t<U>>>::value \endcode is
true. The parameter is wrapped in a terminal expression.
Example:
\snippet user_macros_snippets.cpp USER_UDT_UDT_BINARY_OPERATOR
\param op_name The operator to be overloaded; this must be one of the \b
binary enumerators in <code>expr_kind</code>, without the
<code>expr_kind::</code> qualification.
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
\param t_udt_trait A trait template to use to constrain which types are
accepted as \a T template parameters to the defined operator overload.
\param u_udt_trait A trait template to use to constrain which types are
accepted as \a U template parameters to the defined operator overload.
*/
#define BOOST_YAP_USER_UDT_UDT_BINARY_OPERATOR( \
op_name, expr_template, t_udt_trait, u_udt_trait) \
template<typename T, typename U> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(T && lhs, U && rhs) \
->::boost::yap::detail::udt_udt_binary_op_result_t< \
expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
U, \
t_udt_trait, \
u_udt_trait> \
{ \
using result_types = ::boost::yap::detail::udt_udt_binary_op_result< \
expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
U, \
t_udt_trait, \
u_udt_trait>; \
using lhs_type = typename result_types::lhs_type; \
using rhs_type = typename result_types::rhs_type; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return {tuple_type{ \
lhs_type{static_cast<T &&>(lhs)}, \
rhs_type{static_cast<U &&>(rhs)}, \
}}; \
}
/** Defines a free/non-member operator overload for binary operator \a op_name
that produces an expression instantiated from the \a expr_template
expression template.
The \a lhs and \a rhs parameters to the defined operator overload may be any
types that are \b not expressions. Each parameter is wrapped in a terminal
expression.
At least one of the parameters to the defined operator overload must be a
type \c T for which \code
udt_trait<std::remove_cv_t<std::remove_reference_t<T>>>::value \endcode is
true.
Example:
\snippet user_macros_snippets.cpp USER_UDT_ANY_BINARY_OPERATOR
\param op_name The operator to be overloaded; this must be one of the \b
binary enumerators in <code>expr_kind</code>, without the
<code>expr_kind::</code> qualification.
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
\param udt_trait A trait template to use to constrain which types are
accepted as template parameters to the defined operator overload.
*/
#define BOOST_YAP_USER_UDT_ANY_BINARY_OPERATOR( \
op_name, expr_template, udt_trait) \
template<typename T, typename U> \
constexpr auto operator BOOST_YAP_INDIRECT_CALL(op_name)(T && lhs, U && rhs) \
->::boost::yap::detail::udt_any_binary_op_result_t< \
expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
U, \
udt_trait> \
{ \
using result_types = ::boost::yap::detail::udt_any_binary_op_result< \
expr_template, \
::boost::yap::expr_kind::op_name, \
T, \
U, \
udt_trait>; \
using lhs_type = typename result_types::lhs_type; \
using rhs_type = typename result_types::rhs_type; \
using tuple_type = ::boost::hana::tuple<lhs_type, rhs_type>; \
return {tuple_type{lhs_type{static_cast<T &&>(lhs)}, \
rhs_type{static_cast<U &&>(rhs)}}}; \
}
/** Defines user defined literal template that creates literal placeholders
instantiated from the \a expr_template expression template. It is
recommended that you put this in its own namespace.
\param expr_template The expression template to use to instantiate the
result expression. \a expr_template must be an \ref
ExpressionTemplate.
*/
#define BOOST_YAP_USER_LITERAL_PLACEHOLDER_OPERATOR(expr_template) \
template<char... c> \
constexpr auto operator"" _p() \
{ \
using i = ::boost::hana::llong< \
::boost::hana::ic_detail::parse<sizeof...(c)>({c...})>; \
static_assert(1 <= i::value, "Placeholders must be >= 1."); \
return expr_template< \
::boost::yap::expr_kind::terminal, \
::boost::hana::tuple<::boost::yap::placeholder<i::value>>>{}; \
}
#endif

View File

@@ -0,0 +1,13 @@
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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_YAP_YAP_HPP_INCLUDED
#define BOOST_YAP_YAP_HPP_INCLUDED
#include <boost/yap/algorithm.hpp>
#include <boost/yap/expression.hpp>
#endif