哪种优化技术支持按值传递的Functor被内联?
关于无状态函数传递的优化技术探究
我希望在编译期高效传递无状态函数,目前有两种实现方案:
第一种是将Functor作为函数参数传递:
template<typename Functor> bool PassAsArgument(int arg1, int arg2, Functor functor);
第二种是将函数指针作为模板参数传递:
template<bool (*Function)(int, int)> bool PassAsTemplateParameter(int arg1, int arg2);
虽然第二种方案看起来更适合编译期计算,但《Effective STL》第39条、C标准库(如std::sort、std::make_heap)、C核心准则(T.40)以及Stack Overflow的相关回答都不推荐这种写法。我在Godbolt上测试了两种实现,发现两种方式都能实现预期优化——std::less<int>被成功内联。
测试代码1:按参数传递Functor
#include <functional> template<typename Functor> bool PassAsArgument(int arg1, int arg2, Functor functor){ return functor(arg1, arg2); } template bool PassAsArgument(int, int, std::less<int>);
对应的编译结果:
bool PassAsArgument<std::less<int> >(int, int, std::less<int>): cmp edi, esi setl al ret
测试代码2:按模板参数传递函数指针
inline bool LessThan(int a, int b){ return a < b; } template<bool (*Function)(int, int)> bool PassAsTemplateParameter(int arg1, int arg2){ return Function(arg1, arg2); } template bool PassAsTemplateParameter<LessThan>(int, int);
对应的编译结果:
bool PassAsTemplateParameter<&(LessThan(int, int))>(int, int): cmp edi, esi setl al ret
我希望遵循规范,但担心在复杂场景下优化失效,比如:
- 若
Functor并非最后一个参数会怎样? - 若向
PassAsArgument传递有状态Functor会怎样? - 若需要传递多个
Functor会怎样? - 若需要在
PassAsArgument内部将Functor传递给func2会怎样? - 若将
Functor的副本保存为类的数据成员会怎样?
作为探究的起点,我想知道:哪种优化技术允许按值传递的Functor被内联?
回答
允许按值传递的无状态Functor被内联的核心技术是模板实例化结合全程序优化与函数内联,具体细节如下:
- 模板特化的可见性:当显式实例化
PassAsArgument<std::less<int>>时,编译器能获取std::less<int>::operator()的完整定义(标准库模板的实现对编译器可见),因此可直接将operator()的逻辑内联到PassAsArgument的实例化函数中。 - 空对象消除:无状态Functor(如
std::less<int>无任何非静态数据成员)按值传递时,编译器会优化掉空对象的存储——这类参数没有需要保存的状态,传递过程无额外开销,也不会阻碍内联。 - 跨函数内联优化:在
-O2或-O3等优化等级下,编译器会进行跨函数内联分析。由于模板函数的实例化版本与Functor的operator()定义处于同一编译单元(或通过全程序优化访问到其他单元的定义),编译器可直接将operator()的代码合并到调用点,完全消除函数调用开销。
这些优化生效的前提:
- Functor的
operator()是inline或其定义对编译器可见(模板函数天然满足此条件); - 编译器启用了足够等级的优化选项;
- Functor无状态,不会因状态存在导致编译器无法完成确定的内联分析。
内容的提问来源于stack exchange,提问作者mbang
相关产品推荐
相关产品推荐

