feat():initial version
This commit is contained in:
598
install/boost_1_75_0/include/boost/yap/detail/algorithm.hpp
Normal file
598
install/boost_1_75_0/include/boost/yap/detail/algorithm.hpp
Normal 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
|
||||
591
install/boost_1_75_0/include/boost/yap/detail/transform.hpp
Normal file
591
install/boost_1_75_0/include/boost/yap/detail/transform.hpp
Normal 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
|
||||
Reference in New Issue
Block a user