关于作为模板参数传递的函数,Ben Supnik提供的社区wiki答案讨论了内联实例化函数模板的问题.
在那个答案是以下代码:
template<typename OP>
int do_op(int a, int b, OP op)
{
return op(a,b,);
}
int add(int a, b) { return a + b; }
int (* func_ptr)(int, int) = add;
int c = do_op(4,5,func_ptr);
Run Code Online (Sandbox Code Playgroud)
答案继续这样说(关于实例化函数模板的最后一行do_op):
显然这不是内联.
我的问题是:为什么很明显这不是内联的?
他所说的(我认为)是该add函数没有内联.换句话说,编译器可能会这样内联do_op:
int c = func_ptr(4, 5);
Run Code Online (Sandbox Code Playgroud)
但它也不会add像这样内联:
int c = 4 + 5;
Run Code Online (Sandbox Code Playgroud)
但是,在这个简单的例子中他可能是错的.
通常,当您通过指针调用函数时,编译器无法知道(在编译时)您将调用的函数,因此它无法内联函数.例:
void f1() { ... }
void f2() { ... }
void callThroughPointer() {
int i = arc4random_uniform(2);
void (*f)() = i ? f2 : f1;
f();
}
Run Code Online (Sandbox Code Playgroud)
在这里,编译器无法知道是否callThroughPointer会打电话f1或f2,所以没有办法为它无论是内联f1或f2在callThroughPointer.
但是,如果编译器可以在编译时证明将调用哪个函数,则允许内联函数.例:
void f1() { ... }
void f2() { ... }
void callThroughPointer2() {
int i = arc4random_uniform(2);
void (*f)() = i ? f2 : f1;
f = f1;
f();
}
Run Code Online (Sandbox Code Playgroud)
在这里,编译器可以证明,f将永远是f1,因此它允许内联f1成callThroughPointer2.(这并不意味着它会内联f1......)
类似地,在您在帖子中引用的示例中,编译器可以证明func_ptr始终add在调用中do_op,因此允许内联add.(这并不意味着它会内联add......)