Acorn
Acorn

Reputation: 1187

Getting Index of a type in a Typelist

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

Answers (3)

rmshark
rmshark

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

Alex Vaskov
Alex Vaskov

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

jbab
jbab

Reputation: 509

You get the error because

IndeOf<T, Ts...>::value

is undefined. It should be

IndexOf<T, TypeList<Ts...>>::value

instead.

Upvotes: 4

Related Questions