我一直在用 C++ 编写一些涉及大量元编程的代码;该代码对一个任务进行建模,该任务在运行时由一系列节点定义,这些节点接受多个输入,并在运行时产生一定数量的输出。输入和输出在有向图中链接。我将节点类型存储在变体中,并且每个节点类定义一个静态 constexpr 变量,该变量或多或少列出了该节点的输入和输出类型。我希望能够获取节点类别的列表,并将其转换为节点所作用的数据类别的列表。
更明确地说,如果我有一个在编译时纯粹跟踪某些类列表的模板,如下所示:
template<class... Args>
struct ClassList{};
我想要某种可以转换列表列表的模板,如下所示:
ClassList<ClassList<int,int,double>, ClassList<double,char>, ClassList<char, char> >
进入内部列表的并集:
ClassList<int,double,char>
对顺序没有特殊要求 - 除了原始列表中出现的每种类型在最终列表中只出现一次 - 如果可能的话,我希望以不会导致编译器爆炸的方式执行此操作。我知道理论上我可以编写一大堆递归模板,将列表连接成一个,然后删除重复项,但该解决方案听起来有点令人讨厌。有更好的办法吗?
最佳答案
在将类型添加到最终列表之前过滤类型的解决方案:
template<class... Ts>
struct class_list {};
template<class... Ts>
struct make_unique {
using type = class_list<Ts...>;
};
template<class... Ts>
struct make_unique<class_list<>, Ts...> : make_unique<Ts...>{};
template<class U, class... Us, class... Ts>
struct make_unique<class_list<U, Us...>, Ts...>
: std::conditional_t<
(std::is_same_v<U, Us> || ...) || (std::is_same_v<U, Ts> || ...),
make_unique<class_list<Us...>, Ts... >,
make_unique<class_list<Us...>, Ts..., U>> {};
template<class... Ts>
using make_unique_class_list = typename make_unique<Ts...>::type;
using T = make_unique_class_list<class_list<int, int, double>,
class_list<double, char>, class_list<char, char>>;
static_assert(std::is_same_v<T, class_list<int, double, char>>);
请注意,以下看起来类似的解决方案也可以工作,但可能太慢,因为它实例化了许多不必要的模板:
template<class U, class... Us, class... Ts>
struct make_unique<class_list<U, Us...>, Ts...>
: std::conditional<
(std::is_same_v<U, Us> || ...) || (std::is_same_v<U, Ts> || ...),
typename make_unique<class_list<Us...>, Ts... >::type,
typename make_unique<class_list<Us...>, Ts..., U>::type> {};
关于C++ 获取可变参数模板参数包中参数的并集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59403783/