C++ 为什么很清楚模板函数实例化不会内联?
关于这一点,Ben Supnik提供的社区wiki答案讨论了内联实例化函数模板的问题 该答案中包含以下代码:C++ 为什么很清楚模板函数实例化不会内联?,c++,templates,C++,Templates,关于这一点,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); 模板 int do_
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);
模板
int do_op(int a,int b,op)
{
返回op(a,b,);
}
intadd(inta,b){返回a+b;}
int(*func_ptr)(int,int)=添加;
int c=do_op(4,5,func_ptr);
答案是这样的(关于最后一行,它实例化了函数模板do_op
):
显然,这不是内联的
我的问题是:为什么这显然不是内联的?他(我想)的意思是add
函数没有内联。换句话说,编译器可以内联执行以下操作:
int c = func_ptr(4, 5);
int c = 4 + 5;
但它也不会像这样内联添加:
int c = func_ptr(4, 5);
int c = 4 + 5;
然而,在这个简单的例子中,他可能是错的
通常,当您通过指针调用函数时,编译器无法知道(在编译时)将调用什么函数,因此无法内联函数。例如:
void f1() { ... }
void f2() { ... }
void callThroughPointer() {
int i = arc4random_uniform(2);
void (*f)() = i ? f2 : f1;
f();
}
void f1() { ... }
void f2() { ... }
void callThroughPointer2() {
int i = arc4random_uniform(2);
void (*f)() = i ? f2 : f1;
f = f1;
f();
}
在这里,编译器无法知道callThroughPointer
是否将调用f1
或f2
,因此它无法在callThroughPointer
中内联f1
或f2
但是,如果编译器可以在编译时证明将调用什么函数,则允许它内联函数。例如:
void f1() { ... }
void f2() { ... }
void callThroughPointer() {
int i = arc4random_uniform(2);
void (*f)() = i ? f2 : f1;
f();
}
void f1() { ... }
void f2() { ... }
void callThroughPointer2() {
int i = arc4random_uniform(2);
void (*f)() = i ? f2 : f1;
f = f1;
f();
}
在这里,编译器可以证明f
将始终是f1
,因此允许将f1
内联到调用指针2
。(这并不意味着它将内联f1
。)
类似地,在您在文章中引用的示例中,编译器可以证明func_ptr
在调用do_op
时总是add
,因此允许内联add
。(这并不意味着它将内联添加。)
为什么这不是内联的
不是。编译器没有理由不能内联该代码段中的所有代码。当通过函数指针调用函数时,编译器不太可能通过函数指针避免调用。只有当编译器能够证明它知道函数指针是用什么初始化的,并且不能更改时,它才有可能避免通过函数指针调用函数,从而内联函数。在引用的设置中,即
int (* func_ptr)(int, int) = add;
函数指针func_ptr
是可修改的,因此不保证编译器永远不会更改。因此,它不可能内联调用add
如果代码片段确实是完整的,那么在初始化过程中会发生一些事情,编译器实际上可以知道func_ptr
被初始化为包含add
,我认为,到目前为止,这里的讨论忽略了要点。首先,由于语法错误,测试代码甚至无法编译。可能是指:
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);
因此,总结一下:通过模板调用函数不会阻止优化器完成其工作。如果在编译时无法安全地确定函数指针的值,那么函数指针可能会造成危害,但如果添加了模板,问题不会恶化。没有理由不这样做,但有很多理由它甚至可能不尝试这样做。如果我没有被误会的话,那么直到最近,C(和C++)编译器甚至都没有为了内联的目的尝试跟踪函数指针。@KonradRudolph-当然,但声明是很明显这不是内联的。一点也不清楚。