如何在不指定模板类型的情况下传递函数模板作为参数
问题场景与需求
现有如下代码结构:使用std::vector<std::shared_ptr<std::variant<Image<ushort>, Image<float>>>>存储不同类型的图像,需要实现通用的包装函数,自动根据variant的实际类型调用对应的模板函数(如equalize<T>),避免重复编写类型判断的冗余代码。
当前的冗余实现示例:
template<typename T> static void equalize(Image<T>& image) { // 实现逻辑 } // 接收GUI信号的处理函数 void applyEqualize(int row) { auto variant = *images[row]; if (std::holds_alternative<Image<ushort>>(variant)) { Image<ushort>& image = std::get<Image<ushort>>(variant); equalize<ushort>(image); } else if (std::holds_alternative<Image<float>>(variant)) { Image<float>& image = std::get<Image<float>>(variant); equalize<float>(image); } } private: std::vector<std::shared_ptr<std::variant<Image<ushort>, Image<float>>>> images;
期望实现一个通用包装器Wrapper,直接传递函数模板(如equalize)即可完成自动类型匹配与调用,但直接传递函数模板会编译失败,原尝试的代码如下:
template <template<class> class F> void Wrapper(F&& f, int row) { auto variant = *images[row]; if (std::holds_alternative<Image<ushort>>(variant)) { Image<ushort>& image = std::get<Image<ushort>>(variant); f<ushort>(image); } else if (std::holds_alternative<Image<float>>(variant)) { Image<float>& image = std::get<Image<float>>(variant); f<float>(image); } } // 期望调用方式 Wrapper(equalize, row);
编译失败的核心原因:函数模板不是一个可直接传递的实体,它是一组函数的集合,无法作为函数参数或模板实参直接传递。
可行解决方案
方法1:用Lambda封装函数模板调用(最灵活)
利用Lambda表达式封装函数模板的调用逻辑,让包装器接受任意可调用对象,并使用std::visit替代冗余的if-else类型判断:
template <typename Func> void Wrapper(Func&& func, int row) { auto& variant = *images[row]; // std::visit会自动匹配variant中的实际类型,调用对应的逻辑 std::visit(std::forward<Func>(func), variant); }
调用时,用Lambda封装equalize的调用(模板参数可自动推导):
Wrapper([](auto& image) { equalize(image); // 编译器自动推导T的类型 }, row);
方法2:用函数对象替代函数模板
将原函数模板改写成带模板operator()的函数对象,这样可以直接传递对象实例给包装器:
// 替换原equalize模板函数 struct Equalize { template <typename T> void operator()(Image<T>& image) { // 原equalize<T>的实现逻辑 } };
包装器保持方法1的实现,调用时直接传递函数对象实例:
Wrapper(Equalize{}, row);
方法3:简化类型判断逻辑(兼容原思路)
如果坚持保留if-else的类型判断方式,可以通过传递模板的"调用器"来实现,本质还是封装模板调用:
template <typename Callable> void Wrapper(Callable&& callable, int row) { auto& variant = *images[row]; if (std::holds_alternative<Image<ushort>>(variant)) { callable(std::get<Image<ushort>>(variant)); } else if (std::holds_alternative<Image<float>>(variant)) { callable(std::get<Image<float>>(variant)); } }
调用时用Lambda封装:
Wrapper([](auto& img) { equalize(img); }, row);
内容的提问来源于stack exchange,提问作者Arnaiz
相关产品推荐
相关产品推荐

