让我们考虑一个简单的 C++ 函数,它将整数范围内的所有值相除:
无效除法( std :: span <int> i , intd ) { for (自动&值: i ) { 值/ = d ; } }
如果除数 d 在编译时已知,则该函数会快得多。例如,如果 d 为 2,编译器可能会优化除法并使用移位和一些廉价指令。所有编译时常量都是如此:编译器通常可以更好地了解常量。
在 C++ 中,模板函数是使用 template 关键字定义的,后跟一个括在尖括号 < > 中的参数(通常是类型参数)。模板参数充当占位符,在调用函数时将替换为实际数据类型。
在C++中,可以将除法参数变成模板参数:
模板< int d > 无效除法( std :: span <int> i ) { for (自动&值: i ) { 值/ = d ; } }
模板函数本身并不是一个函数,而是生成函数的方法:我们提供整数 d 并创建一个函数。这允许编译器使用编译时常量,生成更快的代码。
如果您希望除数在 2 到 6 之间,则可以从通用函数中调用模板函数,如下所示:
void diverge_fast ( std :: span < int > i , int d ) { 如果( d == 2 ) { 返回除法<2> ( i ) ; } 如果( d == 3 ) { 返回除法<3> ( i ) ; } 如果( d == 4 ) { 返回除法<4> ( i ) ; } 如果( d == 5 ) { 返回除法<5> ( i ) ; } 如果( d == 6 ) { 返回除法<6> ( i ) ; } for (自动&值: i ) { 值/ = d ; } }
如果您愿意,您可以使用 switch/case 来完成此操作,但它不会显着简化代码。
不幸的是,我们必须公开一个模板函数,这会在我们的代码库中产生噪音。我们更愿意将所有逻辑保留在一个函数中。我们可以使用 lambda 函数来做到这一点。
在C++ 中, lambda函数(或lambda表达式)是一个匿名内联函数,您可以动态定义它,通常用于短期使用。从 C++20 开始,您就有了模板 lambda 表达式。
我们几乎可以这样做:
void diverge_fast ( std :: span < int > i , int d ) { auto f = [ & i ] < int除数> ( ) { for (自动&值: i ) { 值/ =除数; } } ; 如果( d == 2 ) { 返回f <2> ( ) ; } 如果( d == 3 ) { 返回f <3> ( ) ; } 如果( d == 4 ) { 返回f <4> ( ) ; } 如果( d == 5 ) { 返回f < 5 > ( ) ; } 如果( d == 6 ) { 返回f <6> ( ) ; } for (自动&值: i ) { 值/ = d ; } }
不幸的是,它并不完全有效。给定模板 lambda 表达式,您无法直接传递模板参数,并且您需要一些丑陋的东西(’template operator()<params>’):
void diverge_fast ( std :: span < int > i , int d ) { auto f = [ & i ] < int除数> ( ) { for (自动&值: i ) { 值/ =除数; } } ; 如果( d == 2 ) { 返回f 。模板运算符( ) < 2 > ( ) ; } 如果( d == 3 ) { 返回f 。模板运算符( ) < 3 > ( ) ; } 如果( d == 4 ) { 返回f 。模板运算符( ) < 4 > ( ) ; } 如果( d == 5 ) { 返回f 。模板运算符( ) < 5 > ( ) ; } 如果( d == 6 ) { 返回f 。模板运算符( ) < 6 > ( ) ; } for (自动&值: i ) { 值/ = d ; } }
实际上,它可能仍然是一个不错的选择。它将所有混乱的优化隐藏在函数中。
原文: https://lemire.me/blog/2025/03/15/speeding-up-c-code-with-template-lambdas/