Могу ли я расширить вариант в C ++? - PullRequest
0 голосов
/ 18 сентября 2018

Я не уверен, что это возможно, но скажу, что у меня есть:

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

Теперь в какой-то момент я создаю Class4 и хотел бы расширить my_variant2, чтобы включить все my_variant вместе с Class4 (в общем, т.е. не просто используя другой using...), чтобы я мог сделать что-то вроде создания массива std::array<my_variant2, n>.

Isэто что то можно сделать?

Ответы [ 3 ]

0 голосов
/ 18 сентября 2018
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;

сейчас

extend_type<my_variant, Class4>

- это

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

, хотя я не одобряю вашу индексацию на основе 1.

extend_type< std::tuple<a,b,c>, d, e, f > также работает.

Я могу немного повеселиться с этим ...

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 );
  };
}

, который дает нам триединый оператор в двух вариантах.

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

, где var - конкатенацияварианты типов var1 и var2.

0 голосов
/ 18 сентября 2018

Есть два шага для достижения этой цели.Первый - определить список типов, использованных в оригинальном std::variant, а второй - создать новый тип std::variant с исходными аргументами и добавляемым.

Можно использовать частичную специализацию шаблонов.чтобы написать признак, который получит список типов шаблонов, используемых в данном std::variant:

#include <variant>

template<class T>
struct t_variant_cat;

template<class ... Old>
struct t_variant_cat<std::variant<Old...>> {
    // Old is a parameter pack containing all of 
    //  template arguments of the std::variant
};

Далее мы добавим еще один аргумент шаблона, который указывает тип для добавления, и определим псевдоним для этого нового типа.

#include <variant>

template<class T, class New>
struct t_variant_cat;

template<class ... Old, class New>
struct t_variant_cat<std::variant<Old...>, New> {
    using type = std::variant<Old..., New>;
};

typename t_variant_cat<my_variant, Class4>::type теперь должно дать std::variant<Class1, Class2, Class3, Class4>.Для удобства мы можем добавить псевдоним типа, чтобы избежать необходимости писать typename и ::type каждый раз:

template<class Old, class New>
using t_variant_cat_t = typename t_variant_cat<Old, New>::type;

Использование будет:

#include <variant>

template<class T, class New>
struct t_variant_cat;

template<class ... Old, class New>
struct t_variant_cat<std::variant<Old...>, New> {
    using type = std::variant<Old..., New>;
};

template<class Old, class New>
using t_variant_cat_t = typename t_variant_cat<Old, New>::type;

using old = std::variant<int, float>;
using extended = t_variant_cat_t<old, double>;

// Makes sure this actually works
static_assert(std::is_same_v<extended, std::variant<int, float, double>>,
    "Something is wrong.");
0 голосов
/ 18 сентября 2018

Годен

#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;
}
...