【发布时间】:2026-02-19 20:50:02
【问题描述】:
最初我无法找到解决this 的方法,但当我提出这个问题时,我想到了新的搜索词,我终于找到了答案。我认为这篇文章既可以作为任何有相同问题的人的重定向(因为需要一段时间才能找到),我还想看看是否有任何方法可以改进语法糖,因为答案是 9 年旧的和一些现代的功能当时不可用。该答案的代码:
#include <utility>
template <template<class> class... Mixins>
class Host : public Mixins<Host<Mixins...>>...
{
public:
Host(Mixins<Host>&&... args) : Mixins<Host>(std::forward<Mixins<Host>>(args))... {}
};
template <class Host> struct Mix1 {};
template <class Host> struct Mix2 {};
int main (void)
{
typedef Host<Mix1, Mix2> TopHost;
delete new TopHost(Mix1<TopHost>(), Mix2<TopHost>());
}
我们的目标是消除在每个 mixin 中重复使用 TopHost 的需要,因为它有点烦人,而且(更重要的是)如果错误的类型意外地与 CRTP 一起使用,它可能真的搞砸了。我有一个偷偷摸摸的怀疑它可能是可能的,因为使用可变参数调用模板类型的构造函数当然是可能的(例如 new T(args...))。
理想情况下,我们可以使用如下语法:
auto mix = TopHost(Mix1(args1...), Mix2(args2...), ...);
甚至(以某种方式)从 using 语句中推导出 mixins:
auto mix = TopHost({args1...}, {args2...}, ...);
编辑: 所以,是的,确实,我在不知不觉中为我自己的问题提供了解决方案。第二种语法有效。如前所述,它不需要使用,因此仍然存在用户错误的可能性。 @Evg 的解决方案确实强制了这一点,虽然它更冗长,但它在技术上回答了这个问题,所以我会接受这个答案(现在)。
现在我遇到的问题是,在我的应用程序中,mixin 已经删除了复制构造函数,并且这两种方法都创建了副本(当然,原来的类就是这样设计的)。所以现在问题变成了:有没有办法在不复制的情况下实现语法?我一直在尝试让这样的东西工作,但似乎无法围绕如何扩展不同大小的可变参数模板来解决问题:
template < typename... > struct TypeList {};
template<typename TypeList> struct Variad;
template<typename... Types> struct Variad<TypeList<Types...>> {};
template<template<class> typename ...Args> struct Mixins;
template< class TemplList, class... Lists> struct Host;
template< template<class> class ...Components, template<class...> class T, class... Variads>
struct Host<Mixins<Components...>, T<Variads>...> :
public Components<Host<Mixins<Components...>, T<Variads>...>>...
{
Host(T<Variads>&&... args) : Components<Host<Mixins<Components...>, T<Variads>...>>(std::forward<T<Variads>...>(args))... {}
};
这样使用:
int main() {
using f1 = TypeList<int,int>;
using f2 = TypeList<int>;
using m1 = Mixins<Mix1, Mix2>;
Host<m1, Variad<f1>, Variad<f2>> obj(1,2,3);
}
不一定干净,但在我的情况下更可取。我不太确定其中的扩展究竟是如何工作的,但我基于我尝试创建似乎正常工作的嵌套变量:
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
#define get_type(x) (abi::__cxa_demangle(typeid(x).name(), NULL, NULL, NULL))
template < typename... > struct TypeList {};
template<typename TypeList> struct Variad;
template<typename... Types> struct Variad<TypeList<Types...>> {};
template<typename ...TypeListOne> struct NestedVariad;
template<template<class...> class T, typename...Types>
struct NestedVariad<T<Types>...> { };
int main() {
using f1 = TypeList<int,int>;
using f2 = TypeList<int>;
NestedVariad<Variad<f1>, Variad<f2>> obj;
cout << get_type(obj) << endl;
}
哪个输出:NestedVariad<Variad<TypeList<int, int> >, Variad<TypeList<int> > >
但是对 mixin 类使用类似的方法将所有三个参数传递给每个构造函数,而不是 2 传递给第一个,1 传递给第二个
【问题讨论】:
-
第二种语法有效:demo.
-
@Oliv Heeeey,确实如此。我无意中(有点)回答了我自己的问题。但是,该解决方案 A:不强制使用语法,因此用户仍有可能以原始方式执行此操作,并且 B:要求所有 mixin 实现使用初始化列表的构造函数
标签: c++ variadic-templates multiple-inheritance crtp syntactic-sugar