@@ -502,20 +502,27 @@ constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate<Ts>:
502
502
template <template <typename > class Predicate , typename ... Ts>
503
503
constexpr int constexpr_last () { return constexpr_impl::last (0 , -1 , Predicate<Ts>::value...); }
504
504
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>;
517
520
};
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;
519
526
520
527
// / Defer the evaluation of type T until types Us are instantiated
521
528
template <typename T, typename ... /* Us*/ > struct deferred_type { using type = T; };
0 commit comments