Find a type in a parameter pack
You can hide this implementation in a namespace and use another class that calls your implementation with a default parameter example:
namespace detail
{
// your code as it is in the question
}
template <typename A, typename... B>
struct index_of
{
static int const value = detail::index_of<0, A, B...>::value;
};
Edit
In his comment DyP suggests a simpler way to default I
using an alias
template <typename A, typename... B>
using index_of = detail::index_of<0, A, B...>;
template <typename A, typename B, typename... C>
struct index_of
{
static constexpr int const value =
std::is_same<A, B>{}
? 0
: (index_of<A, C...>::value >= 0) ? 1+index_of<A, C...>::value : -1;
};
template <typename A, typename B>
struct index_of<A, B>
{
static constexpr int const value = std::is_same<A, B>{} -1;
};
Note the std::is_same<A, B>{} -1
uses a conversion from bool
to int
.
Better by deriving from integral_constant
:
template <typename A, typename B, typename... C>
struct index_of
: std::integral_constant
< int,
std::is_same<A, B>{}
? 0
: (index_of<A, C...>{} == -1 ? -1 : 1+index_of<A, C...>{})
>
{};
template <typename A, typename B>
struct index_of<A, B>
: std::integral_constant < int, std::is_same<A, B>{} -1 >
{};
If you don't need to return -1
in case the type isn't found:
(if anyone knows how to incorporate a static_assert
here for a pretty diagnostic message, I'd appreciate a comment/edit)
template <typename A, typename B, typename... C>
struct index_of
: std::integral_constant < std::size_t,
std::is_same<A, B>{} ? 0 : 1+index_of<A, C...>{} >
{};
template <typename A, typename B>
struct index_of<A, B>
: std::integral_constant<std::size_t, 0>
{
constexpr operator std::size_t() const
{
return std::is_same<A, B>{}
? 0
: throw std::invalid_argument("Type not found!");
}
};