基于模板的版本允许编译器内联调用,因为函数的地址在编译时是已知的。显然,缺点是函数的地址has在编译时已知(因为您将其用作模板参数),有时这可能是不可能的。
这给我们带来了第二种情况,其中函数指针只能在运行时确定,从而使编译器无法执行内联,但使您可以灵活地在运行时确定要调用的函数:
bool runtimeBooleanExpr = /* ... */;
doParam(0, runtimeBooleanExpr ? add1 : add2);
但请注意,还有第三种方法:
template<typename F>
void doParam(int i, F f){
std::cout << "Do Param: " << f(i) << "\n";
}
这为您提供了更大的灵活性,并且仍然具有在编译时知道将调用什么函数的优点:
doParam(0, add1);
doParam(0, add2);
而且还允许通过任何可调用对象而不是函数指针:
doParam(0, my_functor());
int fortyTwo = 42;
doParam(0, [=] (int i) { return i + fortyTwo; /* or whatever... */ }
为了完整起见,还有一个fourth方式,使用std::function
:
void doParam(int x, std::function<int(int)> f);
它具有相同级别的通用性(因为您可以传递任何可调用对象),但也允许您在运行时确定可调用对象 - 很可能会带来性能损失,因为(再次)编译器无法进行内联。
有关最后两个选项的进一步讨论,另请参阅StackOverflow 上的问答 https://stackoverflow.com/questions/16435549/when-to-use-stdfunction-instead-of-inheritance/16436690#16436690.