Один забавный способ сделать это - взять ваш variant<Ts...>
и превратить его в пользовательскую иерархию классов, в которой все реализуют определенную статическую функцию-член с другим результатом, который вы можете запросить.
Другими словами, учитывая variant<A, B, C>
, создайте иерархию, которая выглядит следующим образом:
struct base_A {
static integral_constant<int, 0> get(tag<A>);
};
struct base_B {
static integral_constant<int, 1> get(tag<B>);
};
struct base_C {
static integral_constant<int, 2> get(tag<C>);
};
struct getter : base_A, base_B, base_C {
using base_A::get, base_B::get, base_C::get;
};
И затем, decltype(getter::get(tag<T>()))
является индексом (или не компилируется). Надеюсь, это имеет смысл.
<ч />
В реальном коде выше становится:
template <typename T> struct tag { };
template <std::size_t I, typename T>
struct base {
static std::integral_constant<size_t, I> get(tag<T>);
};
template <typename S, typename... Ts>
struct getter_impl;
template <std::size_t... Is, typename... Ts>
struct getter_impl<std::index_sequence<Is...>, Ts...>
: base<Is, Ts>...
{
using base<Is, Ts>::get...;
};
template <typename... Ts>
struct getter : getter_impl<std::index_sequence_for<Ts...>, Ts...>
{ };
И как только вы установите геттер, на самом деле использовать его гораздо проще:
template <typename T, typename V>
struct get_index;
template <typename T, typename... Ts>
struct get_index<T, std::variant<Ts...>>
: decltype(getter<Ts...>::get(tag<T>()))
{ };
<ч />
Это работает только в случае, когда типы различны. Если вам это нужно для работы с независимыми типами, то лучшее, что вы можете сделать, это, вероятно, линейный поиск?
template <typename T, typename>
struct get_index;
template <size_t I, typename... Ts>
struct get_index_impl
{ };
template <size_t I, typename T, typename... Ts>
struct get_index_impl<I, T, T, Ts...>
: std::integral_constant<size_t, I>
{ };
template <size_t I, typename T, typename U, typename... Ts>
struct get_index_impl<I, T, U, Ts...>
: get_index_impl<I+1, T, Ts...>
{ };
template <typename T, typename... Ts>
struct get_index<T, std::variant<Ts...>>
: get_index_impl<0, T, Ts...>
{ };