Find type in parameter package

I am trying to find type A in a parameter package:

 template <int I, typename A, typename B, typename ...C> struct index_of { static constexpr int const value = std::is_same<A, B>::value ? I : index_of<I + 1, A, C...>::value; }; template <int I, typename A, typename B> struct index_of<I, A, B> { static constexpr int const value = std::is_same<A, B>::value ? I : -1; }; 

This seems to work, but I cannot remove the nontype I parameter, which I would like to be the default parameter, but cannot make it that way, due to the parameter package at the end. How to eliminate / hide I to make the metafunction more convenient?

+6
source share
2 answers
 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!"); } }; 
+3
source

You can hide this implementation in the namespace and use another class that calls your implementation with an example default parameter:

 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 offers an easier way to default I using an alias

 template <typename A, typename... B> using index_of = detail::index_of<0, A, B...>; 
+6
source

Source: https://habr.com/ru/post/950211/


All Articles