如何让C++模板函数processArray兼容传值与传引用的回调?
问题描述
现有如下C++代码:processArray是用于处理数组的模板函数,它接受回调函数processItem处理每个数组元素。
template<typename TItem> size_t processArray(const TItem* value, const size_t length, size_t (*processItem)(const TItem)) { size_t output = length; for (auto i = 0; i < length; ++i) { output += processItem(value[i]); } return output; } size_t processInt(const int value) { return value; } size_t processString(const std::string& value) { return value.length(); }
处理int数组时传入processInt可正常编译,但处理std::string数组传入processString会报错——因为回调参数声明为const TItem,无法接受引用类型的参数。
若将processItem参数改为size_t (*processItem)(const TItem&),则传入processInt会报错,传入processString正常。
希望仅声明一次processArray,使其兼容传值和传引用类型的回调,而非重复声明模板,请问该如何实现?
解决方案
方案1:将回调类型设为独立模板参数
直接把回调函数的类型也作为模板参数,让编译器自动推导适配,这是最灵活的方式,还能兼容lambda、函数对象等其他可调用类型:
#include <string> template<typename TItem, typename ProcessFunc> size_t processArray(const TItem* value, const size_t length, ProcessFunc processItem) { size_t output = length; for (auto i = 0; i < length; ++i) { output += processItem(value[i]); } return output; } // 原有的processInt、processString无需修改 size_t processInt(const int value) { return value; } size_t processString(const std::string& value) { return value.length(); } // 测试示例 int main() { int intArr[] = {1,2,3}; processArray(intArr, 3, processInt); // 正常编译 std::string strArr[] = {"foo", "bar", "baz"}; processArray(strArr, 3, processString); // 正常编译 return 0; }
方案2:使用std::function适配(C++11及以上)
如果需要明确回调的签名范围,可以用std::function结合decltype推导数组元素类型,自动适配传值/传引用的回调:
#include <string> #include <functional> template<typename TItem> size_t processArray(const TItem* value, const size_t length, std::function<size_t(decltype(value[0]))> processItem) { size_t output = length; for (auto i = 0; i < length; ++i) { output += processItem(value[i]); } return output; } // 原processInt、processString和测试代码不变
方案3:C++20概念约束(增强类型安全)
如果使用C++20,可以用概念明确约束回调必须能处理数组元素类型,同时用std::invoke统一调用逻辑:
#include <string> #include <concepts> #include <functional> template<typename TItem, typename ProcessFunc> requires std::invocable<ProcessFunc, const TItem> || std::invocable<ProcessFunc, const TItem&> size_t processArray(const TItem* value, const size_t length, ProcessFunc processItem) { size_t output = length; for (auto i = 0; i < length; ++i) { output += std::invoke(processItem, value[i]); } return output; } // 原processInt、processString和测试代码不变
内容的提问来源于stack exchange,提问作者mihails.kuzmins
相关产品推荐
相关产品推荐

