Reputation: 1187
I have a simple TypeList implimentation, like this:
template<typename... Ts>
struct TypeList
{
static constexpr std::size_t size{ sizeof... (Ts) };
};
struct T1
{
};
struct T2
{
};
struct T3
{
};
using Types = mpl::TypeList<T1, T2, T3>;
I want to figure out the index of the type T2
inside of the typelist Types
.
This is what I am currently using, however it only works if the type I am searching for is at the beginning of the typelist. Otherwise, it compiles with the error "value
: undeclared identifier".
template<typename, typename>
struct IndexOf {};
// IndexOf base case: found the type we're looking for.
template <typename T, typename... Ts>
struct IndexOf<T, TypeList<T, Ts...>>
: std::integral_constant<std::size_t, 0>
{
};
// IndexOf recursive case: 1 + IndexOf the rest of the types.
template <typename T, typename TOther, typename... Ts>
struct IndexOf<T, TypeList<TOther, Ts...>>
: std::integral_constant<std::size_t,
1 + IndexOf<T, Ts...>::value>
{
};
Upvotes: 7
Views: 1901
Reputation: 11
This solution is a bit cleaner IMHO
#include <type_traits>
template<typename... Ts>
struct TypeList;
namespace detail
{
template<int64_t N, typename T, typename... Ts>
struct index_of;
template<int64_t N, typename T, typename C>
struct index_of<N, T, C>
{
constexpr static int64_t value = (std::is_same<T,C>::value)? N : -1;
};
template<int64_t N, typename T, typename C, typename... Ts>
struct index_of<N, T, TypeList<C, Ts...>>
{
constexpr static int64_t value = (std::is_same<T, C>::value) ?
N : index_of<N+1, T, TypeList<Ts...>>::value;
};
}
template<typename T, typename TL>
constexpr int64_t IndexOf()
{
return detail::index_of<0, T, TL>::value;
}
int main(int argc, char * argv[])
{
using TL = TypeList<uint8_t, uint16_t, uint32_t, uint64_t,
int8_t, int16_t, int32_t, int64_t>;
std::cout << IndexOf<uint8_t, TL>() << std::endl;
std::cout << IndexOf<int8_t, TL>() << std::endl;
std::cout << IndexOf<double, TL>() << std::endl;
}
Upvotes: 1
Reputation: 248
How about this one? This works from C++17 onwards, but it can easily be made backwards-compatible with C++14 by replacing the std::optional with some hand-written simple constexpr_optional type which doesn't need all the intricacies of full-fledged optional type.
#include <optional>
namespace detail {
template <typename X, typename... Ts>
struct try_find_impl {};
template <typename X, typename T, typename... Ts>
struct try_find_impl<X, T,Ts...> {
static constexpr std::optional<size_t> try_find(size_t index=0) noexcept {
return try_find_impl<X, Ts...>::try_find(index+1);
}
};
template <typename T, typename... Ts>
struct try_find_impl<T, T,Ts...> {
static constexpr std::optional<size_t> try_find(size_t index=0) noexcept {
return {index};
}
};
template <typename X>
struct try_find_impl<X> {
static constexpr std::optional<size_t> try_find(size_t=0) noexcept {
return {};
}
};
}//detail
template <typename X, typename... Ts>
constexpr std::optional<size_t> try_find(size_t index=0) {
return detail::try_find_impl<X, Ts...>::try_find(index);
}
Upvotes: 1
Reputation: 509
You get the error because
IndeOf<T, Ts...>::value
is undefined. It should be
IndexOf<T, TypeList<Ts...>>::value
instead.
Upvotes: 4