From 82ece940fb38b5ddf5c3ec8ae925844d34d567c8 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Wed, 29 Mar 2017 11:55:18 +0200 Subject: [PATCH] Replace first_of_t with exactly_one_t --- include/pybind11/attr.h | 2 +- include/pybind11/common.h | 33 ++++++++++++++++++++------------- include/pybind11/pybind11.h | 9 +++------ 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 7fbdfcbc..d046bddc 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -456,7 +456,7 @@ using is_call_guard = is_instantiation; /// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found) template -using extract_guard_t = typename first_of_t, Extra...>::type; +using extract_guard_t = typename exactly_one_t, Extra...>::type; /// Check the number of named arguments at compile time template : template class Predicate, typename... Ts> constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate::value...); } -// Extracts the first type from the template parameter pack matching the predicate, or Default if none match. -template class Predicate, class Default, class... Ts> struct first_of; -template class Predicate, class Default> struct first_of { - using type = Default; +/// Return the Nth element from the parameter pack +template +struct pack_element { using type = typename pack_element::type; }; +template +struct pack_element<0, T, Ts...> { using type = T; }; + +/// Return the one and only type which matches the predicate, or Default if none match. +/// If more than one type matches the predicate, fail at compile-time. +template class Predicate, typename Default, typename... Ts> +struct exactly_one { + static constexpr auto found = constexpr_sum(Predicate::value...); + static_assert(found <= 1, "Found more than one type matching the predicate"); + + static constexpr auto index = found ? constexpr_first() : 0; + using type = conditional_t::type, Default>; }; -template class Predicate, class Default, class T, class... Ts> -struct first_of { - using type = typename std::conditional< - Predicate::value, - T, - typename first_of::type - >::type; -}; -template class Predicate, class Default, class... T> using first_of_t = typename first_of::type; +template class P, typename Default> +struct exactly_one { using type = Default; }; + +template class Predicate, typename Default, typename... Ts> +using exactly_one_t = typename exactly_one::type; /// Defer the evaluation of type T until types Us are instantiated template struct deferred_type { using type = T; }; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 9a3af8e0..cdf5f1a7 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -888,9 +888,9 @@ class class_ : public detail::generic_type { public: using type = type_; - using type_alias = detail::first_of_t; + using type_alias = detail::exactly_one_t; constexpr static bool has_alias = !std::is_void::value; - using holder_type = detail::first_of_t, options...>; + using holder_type = detail::exactly_one_t, options...>; using instance_type = detail::instance; static_assert(detail::all_of...>::value, @@ -1158,15 +1158,12 @@ public: using class_::def; using class_::def_property_readonly_static; using Scalar = typename std::underlying_type::type; - template using arithmetic_tag = std::is_same; template enum_(const handle &scope, const char *name, const Extra&... extra) : class_(scope, name, extra...), m_entries(), m_parent(scope) { - constexpr bool is_arithmetic = - !std::is_same, - void>::value; + constexpr bool is_arithmetic = detail::any_of...>::value; auto m_entries_ptr = m_entries.inc_ref().ptr(); def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str {