This is actually pretty simple to solve with a template type-trait:
#include <type_traits> // std::integral_constant
#include <cstddef> // std::size_t
// Recursive base template (specialized below)
template <std::size_t Current, typename T, typename...Types>
struct find_type_aux;
// Specialization: If we find a match
template <std::size_t Current, typename T, typename...Types>
struct find_type_aux<Current,T,T,Types...>
: std::integral_constant<std::size_t,Current>
{};
// Specialization: If we haven't found a match, but still have some left in the pack
template <std::size_t Current, typename T, typename Type0, typename...Types>
struct find_type_aux<Current,T,Type0, Types...>
: find_type_aux<Current + 1, Types...> // Strip off first, and search rest. Increment count
{};
// Specialization: If we didn't find a match
template <std::size_t Current, typename T>
struct find_type_aux<Current,T>
: std::integral_constant<std::size_t,static_cast<std::size_t>(-1)>{};
{};
// The interface: Find's "T" and returns the 0-based index.
template <typename T, typename...Types>
struct find_type : find_type_aux<0u,T,Types...>{};
With a trait like this, the found element will be the 0-based index, and non-found will be static_cast<std::size_t>(-1)
. 1
Since you mentioned being 1-indexed with 0
for not found, using find_type<int, Types...>::value + 1
will yield either 0
if not found (due to overflow), or a 1
-indexed result -- as requested.
1 The reason this is not explicitly defined to be 1-indexed is that the current definition can be reused to find the index of any type in a variadic pack -- and most interfaces that operate with types that contain variadics expect 0-indexing (such as std::get
). This can easily be used as the building blocks specifically for int
, such as with a variable template:
template <typename...Types>
constexpr auto find_int_v = find_type<int,Types...>::value + 1;
Which then yields the correct answers from:
int main() {
std::cout << find_int_v<short, long, char> << '\n';
std::cout << find_int_v<int, short, long, char> << '\n';
std::cout << find_int_v<short, long, char, int> << '\n';
return 0;
}
as
0
1
4