使用模板 lambda 加速 C++ 代码 - Daniel Lemire 的博客

  • 有一个简单的 C++函数divide用于将整数范围内的所有值相除:

    • void divide(std::span<int> i, int d),通过循环将每个值除以d
    • 整数除法是昂贵的操作,若除数d在编译时已知,函数可更快,如d为 2 时,编译器可能优化为移位等操作。
  • 可将除法参数变为模板参数:

    • template <int d> void divide(std::span<int> i),模板函数不是函数而是生成函数的“食谱”,提供整数d时创建函数,使编译器能处理编译时常量生成更快代码。
  • 若期望除数在 2 到 6 之间,可从通用函数调用模板函数:

    • void divide_fast(std::span<int> i, int d),通过一系列if判断调用不同的模板函数divide<d>,编译器可生成高效代码。
    • 也可用switch/case,但不能显著简化代码,编译器可通过一系列if从句(如跳转表)生成高效代码。
  • 用 lambda 函数隐藏模板函数的混乱优化:

    • auto f = [&i]<int divisor>() { for (auto& value : i) { value /= divisor; } };,通过if判断调用不同的lambda函数f.operator()<d>
    • 但给定模板 lambda 表达式,不能直接传递模板参数,需通过特殊化模板operator()<params>实现。
  • 特定情况下不用模板也可得到相同编译输出:

    • void divide_fast_simple(std::span<int> i, int d),定义一个普通 lambda 函数[&i](int divisor),通过if判断调用不同的普通函数f(divisor)
  • 在另一端,Paul Dreik 建议用模板元编程和折叠表达式:

    • void divide_fast(std::span<int> i, int d),通过复杂的模板元编程代码实现根据不同除数进行相应操作,在更具挑战性的问题中模板元编程很有用,但此例可能过度。
阅读 8
0 条评论