我认为,到目前为止,这里的讨论中遗漏了要点。首先,由于语法错误,测试代码甚至无法编译。大概意思如下:
template<typename OP>
int do_op(int a, int b, OP op) { return op(a,b); }
int add(int a, int b) { return a + b; }
int (*func_ptr)(int, int) = add;
int c = do_op(4, 5, func_ptr);
// int c = (*func_ptr)(4, 5);
编译后,编译器将发出代码以实际调用 add() 函数。但是,当没有模板 as 编写时int c = (*func_ptr)(4, 5);
,编译器也会发出对 add() 的调用。这是因为func_ptr
在这个示例代码中是全局定义的,并且编译器必须注意另一个线程中的某些代码在其初始化和后续使用之间修改 func_ptr 的可能性。但这是全局可见函数指针的属性,与模板无关!除了一些本地标签的名称外,带有优化器的 GCC 为通过 func_ptr 对 add() 的模板化和非模板化调用产生完全相同的汇编器输出。不同的标签名称意味着,由于模板,优化器必须多转一轮,因此编译时间增加(就像所有模板一样),但代码和代码运行时间是相同的。
如果将 func_ptr 移动到函数内部的局部变量中,如下例所示,编译器可以肯定地跟踪对 func_ptr 的所有访问,从而优化所有内容,甚至不再调用 add() 函数,既不直接也不调用通过函数指针:
int testf(void) {
int (*func_ptr)(int, int) = add;
return do_op(4, 5, func_ptr);
}
所以,总结一下:通过模板调用函数不会阻止优化器的工作。如果函数指针的值不能在编译时安全地确定,那么函数指针可能会造成伤害,但如果添加了模板,该问题不会恶化。