Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I extend variant in C++?

I'm not sure that this is possible, but say I have:

using my_variant = std::variant<Class1, Class2, Class3>;

Now at some point, I create a Class4 and would like to extend my_variant2 to include all of my_variant along with Class4 (in a general way, i.e. not just using another using...) so that I can do something like create an array std::array<my_variant2, n>.

Is this something that can be done?

like image 836
Sebastian Avatar asked Sep 18 '18 20:09

Sebastian


2 Answers

godbolted

#include <variant>

template <typename T, typename... Args> struct concatenator;

template <typename... Args0, typename... Args1>
struct concatenator<std::variant<Args0...>, Args1...> {
    using type = std::variant<Args0..., Args1...>;
};

int main() {
    using type_t = std::variant<int, char, double>;
    static_assert(
        std::is_same_v<
            concatenator<type_t, float, short>::type,
            std::variant<int, char, double, float, short>>);
    return 0;
}
like image 104
bobah Avatar answered Nov 02 '22 05:11

bobah


namespace impl_details {
  template<class Var, class...Ts>
  struct extend_type;
  template<template<class...>class Z, class...Vs, class...Ts>
  struct extend_type<Z<Vs...>, Ts...> {
    using type=Z<Vs..., Ts...>;
  };
}
template<class Var, class...Ts>
using extend_type = typename impl_details::extend_type<Var, Ts...>::type;

now

extend_type<my_variant, Class4>

is

std::variant<Class1, Class2, Class3, Class4>

althought I disapprove of your 1-based indexing.

extend_type< std::tuple<a,b,c>, d, e, f > also works.

I can have some fun with this...

namespace impl_details {
  template<class Lhs, class Rhs>
  struct type_cat;
  template<template<class...>class Z, class...Lhs, class...Rhs>
  struct type_cat<Z<Lhs...>, Z<Rhs...>> {
    using type=Z<Lhs..., Rhs...>;
  };
}
template<class Lhs, class Rhs>
using type_cat = typename impl_details::type_cat<Lhs, Rhs>::type;


auto variant_trinary( bool b ) {
  return [b](auto&& lhs, auto&& rhs) {
    using R=type_cat< std::decay_t<decltype(lhs)>, std::decay_t<decltype(rhs)> >;
    auto as_R = [](auto&&x)->R{ return decltype(x)(x)); };
    if (b)
      return std::visit( as_R, lhs );
    else
      return std::visit( as_R, rhs );
  };
}

which gives us the trinary operator on two variants.

auto var = variant_trinary(bool_expr)( var1, var2 );

where var is the concatination of the variant types of var1 and var2.

like image 43
Yakk - Adam Nevraumont Avatar answered Nov 02 '22 05:11

Yakk - Adam Nevraumont