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 that std::is_same<A, B>{} -1 uses the conversion from bool to int .
Better get 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 if the type is not found: (if anyone knows how to enable static_assert here for a pretty diagnostic message, I will be grateful for the comment / change)
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!"); } };