You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建可变参数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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 10:45:03