264 lines
13 KiB
C++
264 lines
13 KiB
C++
/*!
|
|
@file
|
|
Defines `boost::hana::_`.
|
|
|
|
@copyright Louis Dionne 2013-2016
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
|
*/
|
|
|
|
#ifndef BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP
|
|
#define BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP
|
|
|
|
#include <boost/hana/basic_tuple.hpp>
|
|
#include <boost/hana/config.hpp>
|
|
#include <boost/hana/detail/create.hpp>
|
|
#include <boost/hana/detail/decay.hpp>
|
|
|
|
#include <cstddef>
|
|
#include <utility>
|
|
|
|
|
|
BOOST_HANA_NAMESPACE_BEGIN
|
|
//! @ingroup group-functional
|
|
//! Create simple functions representing C++ operators inline.
|
|
//!
|
|
//! Specifically, `_` is an object used as a placeholder to build
|
|
//! function objects representing calls to C++ operators. It works
|
|
//! by overloading the operators between `_` and any object so that
|
|
//! they return a function object which actually calls the corresponding
|
|
//! operator on its argument(s). Hence, for any supported operator `@`:
|
|
//! @code
|
|
//! (_ @ _)(x, y) == x @ y
|
|
//! @endcode
|
|
//!
|
|
//! Operators may also be partially applied to one argument inline:
|
|
//! @code
|
|
//! (x @ _)(y) == x @ y
|
|
//! (_ @ y)(x) == x @ y
|
|
//! @endcode
|
|
//!
|
|
//! When invoked with more arguments than required, functions created with
|
|
//! `_` will discard the superfluous instead of triggering an error:
|
|
//! @code
|
|
//! (_ @ _)(x, y, z...) == x @ y
|
|
//! @endcode
|
|
//!
|
|
//! This makes functions created with `_` easier to use in higher-order
|
|
//! algorithms, which sometime provide more information than necessary
|
|
//! to their callbacks.
|
|
//!
|
|
//! ### Supported operators
|
|
//! - Arithmetic: binary `+`, binary `-`, `/`, `*`, `%`, unary `+`, unary `-`
|
|
//! - Bitwise: `~`, `&`, `|`, `^`, `<<`, `>>`
|
|
//! - Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`
|
|
//! - %Logical: `||`, `&&`, `!`
|
|
//! - Member access: `*` (dereference), `[]` (array subscript)
|
|
//! - Other: `()` (function call)
|
|
//!
|
|
//! More complex functionality like the ability to compose placeholders
|
|
//! into larger function objects inline are not supported. This is on
|
|
//! purpose; you should either use C++14 generic lambdas or a library
|
|
//! like [Boost.Phoenix][] if you need bigger guns. The goal here is
|
|
//! to save you a couple of characters in simple situations.
|
|
//!
|
|
//! ### Example
|
|
//! @include example/functional/placeholder.cpp
|
|
//!
|
|
//! [Boost.Phoenix]: http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html
|
|
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
|
constexpr unspecified _{};
|
|
#else
|
|
namespace placeholder_detail {
|
|
template <typename I>
|
|
struct subscript {
|
|
I i;
|
|
|
|
template <typename Xs, typename ...Z>
|
|
constexpr auto operator()(Xs&& xs, Z const& ...) const&
|
|
-> decltype(static_cast<Xs&&>(xs)[i])
|
|
{ return static_cast<Xs&&>(xs)[i]; }
|
|
|
|
template <typename Xs, typename ...Z>
|
|
constexpr auto operator()(Xs&& xs, Z const& ...) &
|
|
-> decltype(static_cast<Xs&&>(xs)[i])
|
|
{ return static_cast<Xs&&>(xs)[i]; }
|
|
|
|
template <typename Xs, typename ...Z>
|
|
constexpr auto operator()(Xs&& xs, Z const& ...) &&
|
|
-> decltype(static_cast<Xs&&>(xs)[std::declval<I>()])
|
|
{ return static_cast<Xs&&>(xs)[std::move(i)]; }
|
|
};
|
|
|
|
template <typename F, typename Xs, std::size_t ...i>
|
|
constexpr decltype(auto) invoke_impl(F&& f, Xs&& xs, std::index_sequence<i...>) {
|
|
return static_cast<F&&>(f)(hana::get_impl<i>(static_cast<Xs&&>(xs).storage_)...);
|
|
}
|
|
|
|
template <typename ...X>
|
|
struct invoke;
|
|
|
|
struct placeholder {
|
|
struct secret { };
|
|
|
|
template <typename X>
|
|
constexpr decltype(auto) operator[](X&& x) const
|
|
{ return detail::create<subscript>{}(static_cast<X&&>(x)); }
|
|
|
|
template <typename ...X>
|
|
constexpr invoke<typename detail::decay<X>::type...>
|
|
operator()(X&& ...x) const {
|
|
return {secret{}, static_cast<X&&>(x)...};
|
|
}
|
|
};
|
|
|
|
template <typename ...X>
|
|
struct invoke {
|
|
template <typename ...Y>
|
|
constexpr invoke(placeholder::secret, Y&& ...y)
|
|
: storage_{static_cast<Y&&>(y)...}
|
|
{ }
|
|
|
|
basic_tuple<X...> storage_;
|
|
|
|
template <typename F, typename ...Z>
|
|
constexpr auto operator()(F&& f, Z const& ...) const& -> decltype(
|
|
static_cast<F&&>(f)(std::declval<X const&>()...)
|
|
) {
|
|
return invoke_impl(static_cast<F&&>(f), *this,
|
|
std::make_index_sequence<sizeof...(X)>{});
|
|
}
|
|
|
|
template <typename F, typename ...Z>
|
|
constexpr auto operator()(F&& f, Z const& ...) & -> decltype(
|
|
static_cast<F&&>(f)(std::declval<X&>()...)
|
|
) {
|
|
return invoke_impl(static_cast<F&&>(f), *this,
|
|
std::make_index_sequence<sizeof...(X)>{});
|
|
}
|
|
|
|
template <typename F, typename ...Z>
|
|
constexpr auto operator()(F&& f, Z const& ...) && -> decltype(
|
|
static_cast<F&&>(f)(std::declval<X&&>()...)
|
|
) {
|
|
return invoke_impl(static_cast<F&&>(f), static_cast<invoke&&>(*this),
|
|
std::make_index_sequence<sizeof...(X)>{});
|
|
}
|
|
};
|
|
|
|
#define BOOST_HANA_PLACEHOLDER_BINARY_OP(op, op_name) \
|
|
template <typename X> \
|
|
struct op_name ## _left { \
|
|
X x; \
|
|
\
|
|
template <typename Y, typename ...Z> \
|
|
constexpr auto operator()(Y&& y, Z const& ...) const& -> decltype( \
|
|
std::declval<X const&>() op static_cast<Y&&>(y)) \
|
|
{ return x op static_cast<Y&&>(y); } \
|
|
\
|
|
template <typename Y, typename ...Z> \
|
|
constexpr auto operator()(Y&& y, Z const& ...) & -> decltype( \
|
|
std::declval<X&>() op static_cast<Y&&>(y)) \
|
|
{ return x op static_cast<Y&&>(y); } \
|
|
\
|
|
template <typename Y, typename ...Z> \
|
|
constexpr auto operator()(Y&& y, Z const& ...) && -> decltype( \
|
|
std::declval<X>() op static_cast<Y&&>(y)) \
|
|
{ return std::move(x) op static_cast<Y&&>(y); } \
|
|
}; \
|
|
\
|
|
template <typename Y> \
|
|
struct op_name ## _right { \
|
|
Y y; \
|
|
\
|
|
template <typename X, typename ...Z> \
|
|
constexpr auto operator()(X&& x, Z const& ...) const& -> decltype( \
|
|
static_cast<X&&>(x) op std::declval<Y const&>()) \
|
|
{ return static_cast<X&&>(x) op y; } \
|
|
\
|
|
template <typename X, typename ...Z> \
|
|
constexpr auto operator()(X&& x, Z const& ...) & -> decltype( \
|
|
static_cast<X&&>(x) op std::declval<Y&>()) \
|
|
{ return static_cast<X&&>(x) op y; } \
|
|
\
|
|
template <typename X, typename ...Z> \
|
|
constexpr auto operator()(X&& x, Z const& ...) && -> decltype( \
|
|
static_cast<X&&>(x) op std::declval<Y>()) \
|
|
{ return static_cast<X&&>(x) op std::move(y); } \
|
|
}; \
|
|
\
|
|
struct op_name { \
|
|
template <typename X, typename Y, typename ...Z> \
|
|
constexpr auto operator()(X&& x, Y&& y, Z const& ...) const -> decltype(\
|
|
static_cast<X&&>(x) op static_cast<Y&&>(y)) \
|
|
{ return static_cast<X&&>(x) op static_cast<Y&&>(y); } \
|
|
}; \
|
|
\
|
|
template <typename X> \
|
|
constexpr decltype(auto) operator op (X&& x, placeholder) \
|
|
{ return detail::create<op_name ## _left>{}(static_cast<X&&>(x)); } \
|
|
\
|
|
template <typename Y> \
|
|
constexpr decltype(auto) operator op (placeholder, Y&& y) \
|
|
{ return detail::create<op_name ## _right>{}(static_cast<Y&&>(y)); } \
|
|
\
|
|
inline constexpr decltype(auto) operator op (placeholder, placeholder) \
|
|
{ return op_name{}; } \
|
|
/**/
|
|
|
|
#define BOOST_HANA_PLACEHOLDER_UNARY_OP(op, op_name) \
|
|
struct op_name { \
|
|
template <typename X, typename ...Z> \
|
|
constexpr auto operator()(X&& x, Z const& ...) const \
|
|
-> decltype(op static_cast<X&&>(x)) \
|
|
{ return op static_cast<X&&>(x); } \
|
|
}; \
|
|
\
|
|
inline constexpr decltype(auto) operator op (placeholder) \
|
|
{ return op_name{}; } \
|
|
/**/
|
|
// Arithmetic
|
|
BOOST_HANA_PLACEHOLDER_UNARY_OP(+, unary_plus)
|
|
BOOST_HANA_PLACEHOLDER_UNARY_OP(-, unary_minus)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(+, plus)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(-, minus)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(*, times)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(/, divide)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(%, modulo)
|
|
|
|
// Bitwise
|
|
BOOST_HANA_PLACEHOLDER_UNARY_OP(~, bitwise_not)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(&, bitwise_and)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(|, bitwise_or)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(^, bitwise_xor)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(<<, left_shift)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(>>, right_shift)
|
|
|
|
// Comparison
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(==, equal)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(!=, not_equal)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(<, less)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(<=, less_equal)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(>, greater)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(>=, greater_equal)
|
|
|
|
// Logical
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(||, logical_or)
|
|
BOOST_HANA_PLACEHOLDER_BINARY_OP(&&, logical_and)
|
|
BOOST_HANA_PLACEHOLDER_UNARY_OP(!, logical_not)
|
|
|
|
// Member access (array subscript is a member function)
|
|
BOOST_HANA_PLACEHOLDER_UNARY_OP(*, dereference)
|
|
|
|
// Other (function call is a member function)
|
|
|
|
#undef BOOST_HANA_PREFIX_PLACEHOLDER_OP
|
|
#undef BOOST_HANA_BINARY_PLACEHOLDER_OP
|
|
} // end namespace placeholder_detail
|
|
|
|
constexpr placeholder_detail::placeholder _{};
|
|
#endif
|
|
BOOST_HANA_NAMESPACE_END
|
|
|
|
#endif // !BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP
|