This can be done with a recursive template. Recursion terminates early when a prime is found.
// Base failure case: our list is empty (or the specialization below would match)
template <int, int...>
struct find_prime_impl {
static constexpr int value = -1;
};
// Specialization for at least one item remaining. If it's prime, the current
// index is assigned to value; otherwise we recurse with an incremented index,
// and without the first item.
template <int Index, int Head, int... Tail>
struct find_prime_impl<Index, Head, Tail...> {
static constexpr int value = [] {
if constexpr (is_prime<Head>::value) {
return Index;
} else {
return find_prime_impl<Index + 1, Tail...>::value;
}
}();
};
// Calls the recursive template with the initial index 0.
template <int... Values>
struct find_prime : find_prime_impl<0, Values...> {};
The immediately-invoked lambda lets us use if constexpr
which means that the compiler can skip instantiating the recursive use of find_prime_impl
when the terminating case is met. The ternary operator does not "short-circuit" instantiation in this way and would still instantiate the entire recursive chain all the way down to find_prime_impl<Index>
.
(Demo)
To directly use std::integer_sequence
, tweak the implementation to expect it:
// Failure case when the type isn't std::integer_sequence
template <int, typename>
struct find_prime_impl {};
// Failure case when our list is empty (or the specialization below would match)
template <typename TInt, int Index>
struct find_prime_impl<Index, std::integer_sequence<TInt>> {
static constexpr int value = -1;
};
// Specialization for at least one item remaining. If it's prime, the current
// index is assigned to value; otherwise we recurse with an incremented index,
// and without the first item.
template <typename TInt, int Index, TInt Head, TInt... Tail>
struct find_prime_impl<Index, std::integer_sequence<TInt, Head, Tail...>> {
static constexpr int value = [] {
if constexpr (is_prime<Head>::value) {
return Index;
} else {
return find_prime_impl<
Index + 1,
std::integer_sequence<TInt, Tail...>
>::value;
}
}();
};
// Calls the recursive template with the initial index 0.
template <typename T>
struct find_prime : find_prime_impl<0, T> {};