按给定条件拆分给定 std::variant 类型

Ale*_*sky 20 c++ c++17 std-variant

如何通过给定的变体类型

using V = std::variant<bool, char, std::string, int, float, double, std::vector<int>>;
Run Code Online (Sandbox Code Playgroud)

声明两种变体类型

using V1 = std::variant<bool, char, int, float, double>;
using V2 = std::variant<std::string, std::vector<int>>;
Run Code Online (Sandbox Code Playgroud)

whereV1包括所有算术类型VV2包括所有非算术类型V

V 可以是模板类的参数,例如:

template <class V>
struct TheAnswer
{
    using V1 = ?;
    using V2 = ?;
};
Run Code Online (Sandbox Code Playgroud)

一般来说,标准可以是这样的constexpr变量:

template <class T>
constexpr bool filter;
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 14

使用Boost.Mp11,这是一个简短的单行(一如既往):

using V1 = mp_filter<std::is_arithmetic, V>;
using V2 = mp_remove_if<V, std::is_arithmetic>;
Run Code Online (Sandbox Code Playgroud)

您还可以使用:

using V1 = mp_copy_if<V, std::is_arithmetic>;
Run Code Online (Sandbox Code Playgroud)

使两者更加对称。


或者,

using P = mp_partition<V, std::is_arithmetic>;
using V1 = mp_first<P>;
using V2 = mp_second<P>;
Run Code Online (Sandbox Code Playgroud)

  • @MaximEgorushkin 在我看来,这是最好的元编程库。我这里有很多以“使用 Boost.Mp11,这是一个简短的单行文字”开头的答案 (4认同)
  • @AlexeyStarinsky 阅读文档,它还链接到 Peter 写的一些帖子,内容非常丰富。 (3认同)

Que*_*tin 6

如果出于某种原因您不想使用 Barry 简短而合理的答案,这里有一个两者都不是(感谢 @ xskxzr删除尴尬的“引导程序”专业化,并感谢 @ max66警告我不要出现空的变体极端情况) :

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>;
Run Code Online (Sandbox Code Playgroud)

在 Wandbox 上实时观看