Split a given std::variant type by a given criteria

Alexey Starinsky :

How to by a given variant type

using V = std::variant<bool, char, std::string, int, float, double, std::vector<int>>;

declare two variant types

using V1 = std::variant<bool, char, int, float, double>;
using V2 = std::variant<std::string, std::vector<int>>;

where V1 includes all the arithmetic types from V and V2 includes all non-arithmetic types from V?

V can be a parameter of a template class, for example:

template <class V>
struct TheAnswer
{
    using V1 = ?;
    using V2 = ?;
};

in general the criteria can be a constexpr variable like this:

template <class T>
constexpr bool filter;
Quentin :

If for whatever reason you don't want to use Barry's short and reasonable answer, here is one that is neither (thanks @xskxzr for removing the awkward "bootstrap" specialization, and to @max66 for warning me against the empty variant corner case):

namespace detail {
    template <class V>
    struct convert_empty_variant {
        using type = V;
    };

    template <>
    struct convert_empty_variant<std::variant<>> {
        using type = std::variant<std::monostate>;
    };

    template <class V>
    using convert_empty_variant_t = typename convert_empty_variant<V>::type;

    template <class V1, class V2, template <class> class Predicate, class V>
    struct split_variant;

    template <class V1, class V2, template <class> class Predicate>
    struct split_variant<V1, V2, Predicate, std::variant<>> {
        using matching = convert_empty_variant_t<V1>;
        using non_matching = convert_empty_variant_t<V2>;
    };

    template <class... V1s, class... V2s, template <class> class Predicate, class Head, class... Tail>
    struct split_variant<std::variant<V1s...>, std::variant<V2s...>, Predicate, std::variant<Head, Tail...>>
    : std::conditional_t<
        Predicate<Head>::value,
        split_variant<std::variant<V1s..., Head>, std::variant<V2s...>, Predicate, std::variant<Tail...>>,
        split_variant<std::variant<V1s...>, std::variant<V2s..., Head>, Predicate, std::variant<Tail...>>
    > { };
}

template <class V, template <class> class Predicate>
using split_variant = detail::split_variant<std::variant<>, std::variant<>, Predicate, V>;

See it live on Wandbox

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=29335&siteId=1