如何用C++变参模板替换模板参数列表并创建对应智能指针?
变参模板类Foo的改造实现
1. 声明存储TB类型智能指针的容器
由于每个TB类型各不相同,无法用单一类型的std::vector存储,最适配的容器是std::tuple——它天然支持容纳不同类型的元素。直接将std::unique_ptr<TB>作为tuple的元素类型,声明如下:
template <typename TA, typename... TB> class Foo { private: std::tuple<std::unique_ptr<TB>...> m_tb_ptrs; std::unique_ptr<TA> m_ta_ptr; // 原有的TA类型成员 };
如果需要限制TB的数量最多为6个,可在类内添加静态断言做校验:
static_assert(sizeof...(TB) <= 6, "最多支持6个TB类型参数");
2. 在initialise方法中实例化智能指针
已知所有TB的构造函数签名一致,假设构造函数接受的参数类型为Args...,我们可以借助C++17的折叠表达式,逐个初始化tuple中的每个unique_ptr:
template <typename... Args> void initialise(Args&&... args) { // 先初始化TA的智能指针(假设TA构造函数也支持相同参数) m_ta_ptr = std::make_unique<TA>(std::forward<Args>(args)...); // 遍历tuple元素,逐个构造TB对象并赋值给unique_ptr std::apply([&](auto&&... ptrs) { ((ptrs = std::make_unique<std::remove_pointer_t<decltype(ptrs)>>(std::forward<Args>(args)...)), ...); }, m_tb_ptrs); }
这里用std::apply解包tuple的所有元素,再通过折叠表达式依次完成每个unique_ptr的赋值。std::remove_pointer_t<decltype(ptrs)>用于获取unique_ptr指向的原始TB类型。
3. 在execute方法中调用每个智能指针的execute方法
同样利用std::apply和折叠表达式,遍历tuple中的每个智能指针并调用其execute方法:
void execute() { // 先调用TA对象的execute(如果业务需要) m_ta_ptr->execute(); // 依次调用所有TB对象的execute std::apply([](auto&&... ptrs) { (ptrs->execute(), ...); }, m_tb_ptrs); }
折叠表达式中的逗号运算符会按顺序执行每个ptrs->execute()调用,确保所有TB对象的方法都被触发。
完整示例代码
#include <tuple> #include <memory> template <typename TA, typename... TB> class Foo { private: std::tuple<std::unique_ptr<TB>...> m_tb_ptrs; std::unique_ptr<TA> m_ta_ptr; static_assert(sizeof...(TB) <= 6, "最多支持6个TB类型参数"); public: template <typename... Args> void initialise(Args&&... args) { m_ta_ptr = std::make_unique<TA>(std::forward<Args>(args)...); std::apply([&](auto&&... ptrs) { ((ptrs = std::make_unique<std::remove_pointer_t<decltype(ptrs)>>(std::forward<Args>(args)...)), ...); }, m_tb_ptrs); } void execute() { m_ta_ptr->execute(); std::apply([](auto&&... ptrs) { (ptrs->execute(), ...); }, m_tb_ptrs); } }; // 测试用例类 class A { public: A(int x) : m_val(x) {} void execute() { /* 自定义逻辑 */ } private: int m_val; }; class B1 { public: B1(int x) : m_val(x) {} void execute() { /* 自定义逻辑 */ } private: int m_val; }; // 使用示例 int main() { Foo<A, B1> foo; foo.initialise(42); foo.execute(); return 0; }
内容的提问来源于stack exchange,提问作者messenjah
相关产品推荐
相关产品推荐

