如何创建可变参数C++结构体,接受同元数可变可调用对象实现COM对象自动管理
COM可变参数自动管理类实现方案
你遇到的编译错误核心原因是递归实现中的rest是单个AutoManagedCOMObjs<Rest...>类型的成员,不是可展开的参数包,无法直接通过&rest...语法提取所有嵌套的指针地址。
推荐使用基于std::tuple+折叠表达式的更简洁实现,完全兼容你原来的使用习惯,且自动匹配任意数量的COM接口参数:
#include <concepts> #include <tuple> #include <cstdlib> #include <utility> #include <Unknwn.h> template <std::derived_from<IUnknown>... Interfaces> struct AutoManagedCOMObjs { private: std::tuple<Interfaces*...> m_ptrs{}; // 零初始化所有指针为nullptr template <size_t... I> void release_all(std::index_sequence<I...>) noexcept { // 逆序调用Release,和手动实现的释放顺序完全一致 ( [](auto ptr) { if (ptr != nullptr) { ptr->Release(); } }(std::get<sizeof...(I) - 1 - I>(m_ptrs)), ... ); } public: template <std::invocable<Interfaces**...> Invocable> explicit AutoManagedCOMObjs(Invocable&& initializer) { const HRESULT hr = std::forward<Invocable>(initializer)(&std::get<Interfaces*>(m_ptrs)...); if (FAILED(hr)) { // 初始化失败时先释放已经初始化的指针,避免泄漏 release_all(std::index_sequence_for<Interfaces...>{}); std::exit(hr); } } ~AutoManagedCOMObjs() noexcept { release_all(std::index_sequence_for<Interfaces...>{}); } // 禁止拷贝(COM指针默认不支持浅拷贝) AutoManagedCOMObjs(const AutoManagedCOMObjs&) = delete; AutoManagedCOMObjs& operator=(const AutoManagedCOMObjs&) = delete; // 可选:实现移动语义 AutoManagedCOMObjs(AutoManagedCOMObjs&& other) noexcept : m_ptrs(std::exchange(other.m_ptrs, {})) {} AutoManagedCOMObjs& operator=(AutoManagedCOMObjs&& other) noexcept { if (this != &other) { release_all(std::index_sequence_for<Interfaces...>{}); m_ptrs = std::exchange(other.m_ptrs, {}); } return *this; } // 按索引获取指针 template <size_t I> auto get() const noexcept { return std::get<I>(m_ptrs); } // 按接口类型获取指针(仅适用于接口类型不重复的场景) template <std::derived_from<IUnknown> T> auto get() const noexcept { return std::get<T*>(m_ptrs); } };
使用示例
单接口场景
AutoManagedCOMObjs<ID3D11Texture2D> back_buffer_interface([](ID3D11Texture2D** ptr){ return swap_chain->GetBuffer(0, __uuidof(*ptr), reinterpret_cast<void**>(ptr)); }); // 访问指针:back_buffer_interface.get<0>() 或者 back_buffer_interface.get<ID3D11Texture2D>()
多接口场景
AutoManagedCOMObjs<ID3D11Device, ID3D11DeviceContext> d3d_device([](ID3D11Device** ppDev, ID3D11DeviceContext** ppCtx){ return D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, ppDev, nullptr, ppCtx ); }); // 释放顺序:先释放ID3D11DeviceContext,再释放ID3D11Device,和手动实现的逻辑完全一致
内容的提问来源于stack exchange,提问作者Julio Rodrigues
相关产品推荐
相关产品推荐

