Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get index by type in std::variant

Is there a utility in the standard library to get the index of a given type in std::variant? Or should I make one for myself? That is, I want to get the index of B in std::variant<A, B, C> and have that return 1.

There is std::variant_alternative for the opposite operation. Of course, there could be many same types on std::variant's list, so this operation is not a bijection, but it isn't a problem for me (I can have first occurrence of type on list, or unique types on std::variant list).

like image 492
Bargor Avatar asked Sep 12 '18 20:09

Bargor


2 Answers

Update a few years later: My answer here may be a cool answer, but this is the correct one. That is how I would solve this problem today.


We could take advantage of the fact that index() almost already does the right thing.

We can't arbitrarily create instances of various types - we wouldn't know how to do it, and arbitrary types might not be literal types. But we can create instances of specific types that we know about:

template <typename> struct tag { }; // <== this one IS literal

template <typename T, typename V>
struct get_index;

template <typename T, typename... Ts> 
struct get_index<T, std::variant<Ts...>>
    : std::integral_constant<size_t, std::variant<tag<Ts>...>(tag<T>()).index()>
{ };

That is, to find the index of B in variant<A, B, C> we construct a variant<tag<A>, tag<B>, tag<C>> with a tag<B> and find its index.

This only works with distinct types.

like image 93
Barry Avatar answered Oct 07 '22 15:10

Barry


I found this answer for tuple and slightly modificated it:

template<typename VariantType, typename T, std::size_t index = 0>
constexpr std::size_t variant_index() {
    static_assert(std::variant_size_v<VariantType> > index, "Type not found in variant");
    if constexpr (index == std::variant_size_v<VariantType>) {
        return index;
    } else if constexpr (std::is_same_v<std::variant_alternative_t<index, VariantType>, T>) {
        return index;
    } else {
        return variant_index<VariantType, T, index + 1>();
    }
} 

It works for me, but now I'm curious how to do it in old way without constexpr if, as a structure.

like image 24
Bargor Avatar answered Oct 07 '22 16:10

Bargor