C++函数模板如何在函数非类型的前提下接收函数作为参数
函数作为模板实参的传递机制
你看到的写法根本没有跳出C语言的函数传参底层逻辑,只是C++模板的自动类型推导隐藏了函数指针的显式声明,才给人一种"直接把函数本身传进去了"的错觉,核心规则非常明确:
- 第一,C++完全继承了C的函数名退化规则:当函数名作为非引用绑定的实参传递时,会自动发生函数到指针的隐式转换,你代码里写
iterator(arr, 5, increment)和显式写iterator(arr, 5, &increment)没有任何区别,传入的本质就是存了increment函数入口地址的指针,这一步的底层行为和C语言传函数指针完全一致。 - 第二,模板类型参数
F的推导直接匹配退化后的实参类型:"模板只能接收类型或者值作为参数"这个说法本身是对的,这里的F从来不会被推导成什么"函数类型",而是直接推导为实参退化后的函数指针类型,对应你这段代码里的具体类型就是void (*)(int&)。最终模板实例化生成的实际函数,和你手写C风格的函数指针版本没有任何区别:
// 你的代码编译后,模板生成的等价实体代码 void iterator(int *arr, size_t size, void (*f)(int&)) { for (int i = 0; i < size; i++) f(arr[i]); }
常见认知误区
- 不存在"函数先执行再传返回值"的逻辑:编译器只有在看到函数名后面跟调用运算符
()的时候,才会生成函数调用的指令。你传参时只写了函数名,编译器只会做取函数地址、退化为指针的操作,根本不会执行函数逻辑。 - 不要把特殊的引用传参场景当成普遍情况:如果模板形参写成引用形式(比如
F& f),此时函数名不会发生指针退化,F会被推导为纯函数类型void(int&),f是对应函数的引用。但这只是语法层面的包装,底层调用f(arr[i])的时候还是会隐式转成函数指针执行,对上层调用写法没有任何影响,也没有改变"函数通过地址传递"的底层实现。 - C和C在这里的体感差异本质是语法糖:C没有模板自动推导能力,写通用遍历逻辑的时候必须手动写全函数指针的完整类型,没法自动适配不同的元素类型、不同的处理函数签名;C模板会在调用点根据传入的实参自动匹配对应类型,不需要你手动写那串冗长的函数指针声明,才会让你觉得"没用到函数指针"。
内容的提问来源于stack exchange,提问作者interesting
相关产品推荐
相关产品推荐

