C++ 将结构分隔到 "groups" 但允许 `std::variant` 查看 "groups" 中的所有结构

C++ separate structs in to "groups" but allow `std::variant` to see all structs across the "groups"

请看下面的代码。

我在 2 个组中定义了 3 个 structABC)(实际上我还有更多)。这些小组将在我正在建模的现实世界领域内提供上下文。这些组是通过两个 std::variant 实现的(Group1Group2)。

我有一个函数可以 return 任何底层 structs。

为了为函数提供单一 return 类型,我从最初的两个变体(Group1Group2).

但是,我的问题是AllGroups看不到ABC,只能看到Group1Group2

有没有一种方法既可以保持用某种组定义的结构,又可以将它们折叠成一个 std::variant 用于函数 return 类型?

#include <variant>
#include <iostream>

struct A{}; struct B{};
using Group1 = std::variant<A, B>;

struct C{};
using Group2 = std::variant<C>;

using AllGroups = std::variant<Group1, Group2>;

AllGroups getObject()
{
    A a;     // Simple logic for the general question
    AllGroups ret(a);
    return ret;
}

int main()
{
    AllGroups ret = getObject();

    // Here i'd like to check for the individual structs, not Group1 and Group2
    // However I get a compiler error because the AllVariant can only see Group1 and Group2

    std::cout << std::holds_alternative<A>(ret) << std::endl;
}

您可以使用特征将 std::variant<A...>std::variant<B...> 组合以获得 std::variant<A...,B...>:

#include <variant>
#include <iostream>

struct A{}; struct B{};
using Group1 = std::variant<A, B>;

struct C{};
using Group2 = std::variant<C>;

template <typename T1,typename T2> struct combine_variants;

template <typename... A,typename... B>
struct combine_variants<std::variant<A...>,std::variant<B...>> {
    using type = std::variant<A...,B...>;
};


using AllGroups = combine_variants<Group1, Group2>::type;

AllGroups getObject()
{
    A a;     // Simple logic for the general question
    AllGroups ret(a);
    return ret;
}

int main()
{
    AllGroups ret = getObject();

    std::cout << std::holds_alternative<A>(ret) << std::endl;
}

Live Demo

这是另一种将两个变体类型连接在一起以获得合并类型的方法

template <typename... Ts, typename... Us>
auto variant_concat(std::variant<Ts...>, std::variant<Us...>) -> std::variant<Ts..., Us...>;

template <typename V1, typename V2>
using variant_concat_t = decltype(variant_concat(std::declval<V1>(), std::declval<V2>()));

你会像

一样使用它
using AllGroups = variant_concat_t<Group1, Group2>;

这里是你如何做一个特征来产生你想要的类型 - 变体的替代类型的组合。与其他答案不同,它适用于连接两个以上的变体;)

#include <variant>


template<class Variant1, class Variant2, class... Variants> 
struct variant_cat;

template<class... Var1, class... Var2>
struct variant_cat<std::variant<Var1...>, std::variant<Var2...>>
{
    using type = std::variant<Var1..., Var2...>;
};

template<class... Var1, class... Var2, class... Variants>
struct variant_cat<std::variant<Var1...>, std::variant<Var2...>, Variants...>
{
    using type = typename variant_cat<std::variant<Var1..., Var2...>, Variants...>::type;
};

template<class... A>
using variant_cat_t = variant_cat<A...>::type;

// Usage:
variant_cat_t<std::variant<int, char>, std::variant<double, float>, std::variant<std::nullptr_t>> Result;