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

为Vulkan API对象RAII包装器的多模板函数传递多模板参数

解决方案

一、用Lambda捕获简化参数传递

你现在用的Lambda方式其实已经能解决参数问题——让Lambda在构造时捕获需要的外部参数,这样raii_wrapper内部调用_create和_destroy时就不需要额外传参了。

调整你的使用示例:

// 假设创建Instance需要额外参数allocator,销毁需要instance和allocator
auto create_instance = [allocator](const auto& create_info) {
    return vk::createInstance(create_info, allocator);
};
auto destroy_instance = [allocator](vk::Instance instance) {
    instance.destroy(allocator);
};

using raii_instance = raii_wrapper<vk::Instance, decltype(create_instance), decltype(destroy_instance)>;
// 构造raii_wrapper时传入这两个Lambda
raii_instance inst(create_instance, destroy_instance);

再修改raii_wrapper的调用逻辑,把必要参数传给_create:

template<typename VkObjectType, typename VkCreateFunc, typename VkDestroyFunc>
class raii_wrapper {
public:
    // 构造函数接收创建和销毁函数
    raii_wrapper(VkCreateFunc create, VkDestroyFunc destroy)
        : _create(std::move(create)), _destroy(std::move(destroy)) {}

    ~raii_wrapper() {
        // 假设类内存储了VkObjectType实例
        if (_object) {
            _destroy(_object); // 直接调用,Lambda已捕获额外参数
        }
    }
    
    raii_wrapper& operator=(const create_info<VkObjectType>& factory) {
        auto ci = tools::get_CreateInfo<VkObjectType>(factory);
        _object = _create(ci); // 传入create_info,Lambda处理其他参数
        return *this;
    }

private:
    VkObjectType _object{};
    VkCreateFunc _create;
    VkDestroyFunc _destroy;
};

这种方式的优势:

  • 无需在模板中额外声明参数类型,Lambda自动推导并捕获参数
  • 完全适配不同对象的创建/销毁参数差异,不用修改raii_wrapper的模板结构

二、用结构体封装函数与参数(备选方案)

如果不想用Lambda捕获,也可以用结构体封装函数和参数,通过std::invoke调用:

先定义通用封装结构体:

template<typename Func, typename... Args>
struct FuncWithArgs {
    Func func;
    std::tuple<Args...> args;

    template<typename... CallArgs>
    auto operator()(CallArgs&&... callArgs) {
        // 合并调用时的参数与结构体存储的参数后执行函数
        return std::apply([&](auto&&... storedArgs) {
            return std::invoke(func, std::forward<CallArgs>(callArgs)..., std::forward<Args>(storedArgs)...);
        }, args);
    }
};

// 辅助函数快速创建结构体实例
template<typename Func, typename... Args>
auto make_func_with_args(Func&& func, Args&&... args) {
    return FuncWithArgs<std::decay_t<Func>, std::decay_t<Args>...>{
        std::forward<Func>(func),
        std::make_tuple(std::forward<Args>(args)...)
    };
}

使用方式:

// 创建带参数的封装对象
auto create_instance = make_func_with_args(vk::createInstance, allocator);
auto destroy_instance = make_func_with_args([](vk::Instance inst, auto alloc) { inst.destroy(alloc); }, allocator);

using raii_instance = raii_wrapper<vk::Instance, decltype(create_instance), decltype(destroy_instance)>;

raii_wrapper的调用逻辑和之前一致,直接传必要参数(比如create_info)即可,结构体内部会自动合并存储的参数传给函数。

三、模板参数显式声明参数类型(不推荐)

如果一定要在模板里声明参数类型,可以给raii_wrapper额外添加两组参数模板:

template<
    typename VkObjectType,
    typename VkCreateFunc, typename... CreateArgs,
    typename VkDestroyFunc, typename... DestroyArgs
>
class raii_wrapper {
    // ... 这种方式会让模板参数列表极度冗长,使用起来繁琐,违背复用类的初衷
};

这种方案需要每个RAII类型都显式声明所有参数类型,实用性很低,不推荐使用。


内容的提问来源于stack exchange,提问作者user20972572

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 20:40:29