C++11 性能:Lambda 内联与函数模板特化
C++11 Performance: Lambda inlining vs Function template specialization
我的问题是对此进行扩展:Why can lambdas be better optimized by the compiler than plain functions?
重申一下,结论是 lambdas 创建了不同的特化,编译器可以简单地内联这些特化,而函数指针不那么容易内联,因为一组函数原型只有一个特化。考虑到这一点,函数指针模板 as-fast-as/faster lambdas?
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
template <class F>
int operate(int a, int b, F func)
{
return func(a, b);
}
template <int func(int, int)>
int operateFuncTemplate(int a, int b)
{
return func(a, b);
}
int main()
{
// hard to inline (can't determine statically if operate's f is add or sub since its just a function pointer)
auto addWithFuncP = operate(1, 2, add);
auto subWithFuncP = operate(1, 2, sub);
// easy to inline (lambdas are unique so 2 specializations made, each easy to inline)
auto addWithLamda = operate(1, 2, [](int a, int b) { return a + b; });
auto subWithLamda = operate(1, 2, [](int a, int b) { return a - b; });
// also easy to inline? specialization means there are 2 made, instead of just 1 function definition with indirection?
auto addWithFuncT = operateFuncTemplate<add>(1, 2);
auto subWithFuncT = operateFuncTemplate<sub>(1, 2);
}
因此,如果我可以根据性能对它们进行排名,那么:
operatorFuncTemplate
>= operate<LAMBDA>
>= operate<FUNCTIONPTR>
是否存在这种关系在非平凡示例中失败的情况?
如果编译器可以跟踪"this function pointer points to this function",编译器可以通过函数指针内联调用。
有时编译器可以做到这一点。有时他们不能。
除非您将 lambda 存储在函数指针 std::function
或类似的类型擦除包装器中,否则调用 lambda 时的编译器知道 lambda 的类型,因此知道主体拉姆达。编译器可以简单地内联函数调用。
使用函数模板不会改变这一点,除非参数 constexpr
类似于函数非类型模板参数:
template <int func(int, int)>
这就是一个例子。在这里,函数体中的函数模板保证在编译时是已知的。
但是,将 func
传递到其他任何地方,编译器可能会丢失它。
无论如何,任何速度差异都将高度依赖于上下文。有时由内联 lambda 引起的更大的二进制大小会导致比无法内联函数指针更慢的速度,因此性能可以相反。
任何像你试图做出的普遍声明有时都是错误的。
我的问题是对此进行扩展:Why can lambdas be better optimized by the compiler than plain functions?
重申一下,结论是 lambdas 创建了不同的特化,编译器可以简单地内联这些特化,而函数指针不那么容易内联,因为一组函数原型只有一个特化。考虑到这一点,函数指针模板 as-fast-as/faster lambdas?
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
template <class F>
int operate(int a, int b, F func)
{
return func(a, b);
}
template <int func(int, int)>
int operateFuncTemplate(int a, int b)
{
return func(a, b);
}
int main()
{
// hard to inline (can't determine statically if operate's f is add or sub since its just a function pointer)
auto addWithFuncP = operate(1, 2, add);
auto subWithFuncP = operate(1, 2, sub);
// easy to inline (lambdas are unique so 2 specializations made, each easy to inline)
auto addWithLamda = operate(1, 2, [](int a, int b) { return a + b; });
auto subWithLamda = operate(1, 2, [](int a, int b) { return a - b; });
// also easy to inline? specialization means there are 2 made, instead of just 1 function definition with indirection?
auto addWithFuncT = operateFuncTemplate<add>(1, 2);
auto subWithFuncT = operateFuncTemplate<sub>(1, 2);
}
因此,如果我可以根据性能对它们进行排名,那么:
operatorFuncTemplate
>= operate<LAMBDA>
>= operate<FUNCTIONPTR>
是否存在这种关系在非平凡示例中失败的情况?
如果编译器可以跟踪"this function pointer points to this function",编译器可以通过函数指针内联调用。
有时编译器可以做到这一点。有时他们不能。
除非您将 lambda 存储在函数指针 std::function
或类似的类型擦除包装器中,否则调用 lambda 时的编译器知道 lambda 的类型,因此知道主体拉姆达。编译器可以简单地内联函数调用。
使用函数模板不会改变这一点,除非参数 constexpr
类似于函数非类型模板参数:
template <int func(int, int)>
这就是一个例子。在这里,函数体中的函数模板保证在编译时是已知的。
但是,将 func
传递到其他任何地方,编译器可能会丢失它。
无论如何,任何速度差异都将高度依赖于上下文。有时由内联 lambda 引起的更大的二进制大小会导致比无法内联函数指针更慢的速度,因此性能可以相反。
任何像你试图做出的普遍声明有时都是错误的。