为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
相关产品推荐
相关产品推荐

