Skip to content

Commit 82ece94

Browse files
committed
Replace first_of_t with exactly_one_t
1 parent 1ac1903 commit 82ece94

File tree

3 files changed

+24
-20
lines changed

3 files changed

+24
-20
lines changed

include/pybind11/attr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ using is_call_guard = is_instantiation<call_guard, T>;
456456

457457
/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found)
458458
template <typename... Extra>
459-
using extract_guard_t = typename first_of_t<is_call_guard, call_guard<>, Extra...>::type;
459+
using extract_guard_t = typename exactly_one_t<is_call_guard, call_guard<>, Extra...>::type;
460460

461461
/// Check the number of named arguments at compile time
462462
template <typename... Extra,

include/pybind11/common.h

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -502,20 +502,27 @@ constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate<Ts>:
502502
template <template<typename> class Predicate, typename... Ts>
503503
constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate<Ts>::value...); }
504504

505-
// Extracts the first type from the template parameter pack matching the predicate, or Default if none match.
506-
template <template<class> class Predicate, class Default, class... Ts> struct first_of;
507-
template <template<class> class Predicate, class Default> struct first_of<Predicate, Default> {
508-
using type = Default;
509-
};
510-
template <template<class> class Predicate, class Default, class T, class... Ts>
511-
struct first_of<Predicate, Default, T, Ts...> {
512-
using type = typename std::conditional<
513-
Predicate<T>::value,
514-
T,
515-
typename first_of<Predicate, Default, Ts...>::type
516-
>::type;
505+
/// Return the Nth element from the parameter pack
506+
template <size_t N, typename T, typename... Ts>
507+
struct pack_element { using type = typename pack_element<N - 1, Ts...>::type; };
508+
template <typename T, typename... Ts>
509+
struct pack_element<0, T, Ts...> { using type = T; };
510+
511+
/// Return the one and only type which matches the predicate, or Default if none match.
512+
/// If more than one type matches the predicate, fail at compile-time.
513+
template <template<typename> class Predicate, typename Default, typename... Ts>
514+
struct exactly_one {
515+
static constexpr auto found = constexpr_sum(Predicate<Ts>::value...);
516+
static_assert(found <= 1, "Found more than one type matching the predicate");
517+
518+
static constexpr auto index = found ? constexpr_first<Predicate, Ts...>() : 0;
519+
using type = conditional_t<found, typename pack_element<index, Ts...>::type, Default>;
517520
};
518-
template <template<class> class Predicate, class Default, class... T> using first_of_t = typename first_of<Predicate, Default, T...>::type;
521+
template <template<typename> class P, typename Default>
522+
struct exactly_one<P, Default> { using type = Default; };
523+
524+
template <template<typename> class Predicate, typename Default, typename... Ts>
525+
using exactly_one_t = typename exactly_one<Predicate, Default, Ts...>::type;
519526

520527
/// Defer the evaluation of type T until types Us are instantiated
521528
template <typename T, typename... /*Us*/> struct deferred_type { using type = T; };

include/pybind11/pybind11.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -888,9 +888,9 @@ class class_ : public detail::generic_type {
888888

889889
public:
890890
using type = type_;
891-
using type_alias = detail::first_of_t<is_subtype, void, options...>;
891+
using type_alias = detail::exactly_one_t<is_subtype, void, options...>;
892892
constexpr static bool has_alias = !std::is_void<type_alias>::value;
893-
using holder_type = detail::first_of_t<is_holder, std::unique_ptr<type>, options...>;
893+
using holder_type = detail::exactly_one_t<is_holder, std::unique_ptr<type>, options...>;
894894
using instance_type = detail::instance<type, holder_type>;
895895

896896
static_assert(detail::all_of<is_valid_class_option<options>...>::value,
@@ -1158,15 +1158,12 @@ template <typename Type> class enum_ : public class_<Type> {
11581158
using class_<Type>::def;
11591159
using class_<Type>::def_property_readonly_static;
11601160
using Scalar = typename std::underlying_type<Type>::type;
1161-
template <typename T> using arithmetic_tag = std::is_same<T, arithmetic>;
11621161

11631162
template <typename... Extra>
11641163
enum_(const handle &scope, const char *name, const Extra&... extra)
11651164
: class_<Type>(scope, name, extra...), m_entries(), m_parent(scope) {
11661165

1167-
constexpr bool is_arithmetic =
1168-
!std::is_same<detail::first_of_t<arithmetic_tag, void, Extra...>,
1169-
void>::value;
1166+
constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value;
11701167

11711168
auto m_entries_ptr = m_entries.inc_ref().ptr();
11721169
def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str {

0 commit comments

Comments
 (0)