summaryrefslogtreecommitdiff
path: root/boost/hof/is_unpackable.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/hof/is_unpackable.hpp')
-rw-r--r--boost/hof/is_unpackable.hpp115
1 files changed, 115 insertions, 0 deletions
diff --git a/boost/hof/is_unpackable.hpp b/boost/hof/is_unpackable.hpp
new file mode 100644
index 0000000000..1f1e0d26cf
--- /dev/null
+++ b/boost/hof/is_unpackable.hpp
@@ -0,0 +1,115 @@
+/*=============================================================================
+ Copyright (c) 2016 Paul Fultz II
+ is_unpackable.hpp
+ 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_HOF_GUARD_IS_UNPACKABLE_HPP
+#define BOOST_HOF_GUARD_IS_UNPACKABLE_HPP
+
+/// is_unpackable
+/// =============
+///
+/// This is a trait that can be used to detect whether the type can be called
+/// with `unpack`.
+///
+/// Synopsis
+/// --------
+///
+/// template<class T>
+/// struct is_unpackable;
+///
+/// Example
+/// -------
+///
+/// #include <boost/hof.hpp>
+/// #include <cassert>
+///
+/// int main() {
+/// static_assert(boost::hof::is_unpackable<std::tuple<int>>::value, "Failed");
+/// }
+///
+
+#include <boost/hof/unpack_sequence.hpp>
+#include <boost/hof/is_invocable.hpp>
+#include <boost/hof/always.hpp>
+#include <boost/hof/detail/static_const_var.hpp>
+#include <boost/hof/detail/unpack_tuple.hpp>
+
+namespace boost { namespace hof {
+
+namespace detail {
+
+struct unpack_impl_f
+{
+ template<class F, class Sequence>
+ constexpr auto operator()(F&& f, Sequence&& s) const BOOST_HOF_RETURNS
+ (
+ boost::hof::unpack_sequence<typename std::remove_cv<typename std::remove_reference<Sequence>::type>::type>::
+ apply(BOOST_HOF_FORWARD(F)(f), BOOST_HOF_FORWARD(Sequence)(s))
+ );
+};
+
+BOOST_HOF_DECLARE_STATIC_VAR(unpack_impl, unpack_impl_f);
+
+#if BOOST_HOF_CHECK_UNPACK_SEQUENCE
+struct private_unpack_type {};
+template<class Sequence>
+struct unpack_impl_result
+{
+ static_assert(boost::hof::is_invocable<unpack_impl_f, decltype(boost::hof::always(private_unpack_type())), Sequence>::value,
+ "Unpack is invalid for this sequence. The function used to unpack this sequence is not callable."
+ );
+ typedef decltype(boost::hof::detail::unpack_impl(boost::hof::always(private_unpack_type()), std::declval<Sequence>())) type;
+};
+
+template<class Sequence>
+struct is_proper_sequence
+: std::is_same<
+ private_unpack_type,
+ typename unpack_impl_result<Sequence>::type
+>
+{};
+#endif
+template<class Sequence, class=void>
+struct is_unpackable_impl
+: std::true_type
+{
+#if BOOST_HOF_CHECK_UNPACK_SEQUENCE
+ static_assert(is_proper_sequence<Sequence>::value,
+ "Unpack is invalid for this sequence. The function used to unpack this sequence does not invoke the function."
+ );
+#endif
+};
+
+template<class Sequence>
+struct is_unpackable_impl<Sequence, typename detail::holder<
+ typename unpack_sequence<Sequence>::not_unpackable
+>::type>
+: std::false_type
+{};
+
+}
+
+template<class Sequence>
+struct is_unpackable
+: detail::is_unpackable_impl<
+ typename std::remove_cv<typename std::remove_reference<Sequence>::type>::type
+>
+{
+#if BOOST_HOF_CHECK_UNPACK_SEQUENCE
+typedef detail::is_unpackable_impl<
+ typename std::remove_cv<typename std::remove_reference<Sequence>::type>::type
+> base;
+
+typedef std::conditional<base::value, detail::is_proper_sequence<Sequence>, std::true_type> check;
+static_assert(check::type::value,
+ "Unpack is invalid for this sequence. The function used to unpack this sequence does not invoke the function."
+);
+#endif
+};
+
+}} // namespace boost::hof
+
+#endif