【Effective Modern C++】第六章 lambda表达式:34. 考虑lambda而非bind

lambda 全面优于 std::bind(C++14 中无例外)

lambda 相比std::bind更易读、表达力更强、性能更高;仅在 C++11 的两个特殊场景下,std::bind有少量合理用途,而 C++14 中 lambda 的增强特性让std::bind完全失去使用价值。

可读性对比:lambda 直观,std::bind 晦涩且易踩坑

以setAlarm(设置闹钟)为例,对比两者的实现差异:

lambda 版本(清晰易懂)
c++ 复制代码
auto setSoundL = [](Sound s) {
    using namespace std::chrono;
    using namespace std::literals; // C++14时间字面量
    setAlarm(steady_clock::now() + 1h, s, 30s); // 直接调用,参数清晰
};
  • 直接调用目标函数setAlarm,参数传递、求值时机一目了然;
  • 即使是 lambda 新手,也能快速理解 "lambda 的形参s传给setAlarm第二个参数";
  • C++14 的时间字面量(1h、30s)进一步简化代码。
std::bind 版本(晦涩且有陷阱)
c++ 复制代码
// 初始错误版本(求值时机错误)
auto setSoundB = std::bind(setAlarm, steady_clock::now() + 1h, _1, 30s);

// 修正版本(嵌套bind,复杂度飙升)
auto setSoundB = std::bind(setAlarm,
                          std::bind(std::plus<>(), std::bind(steady_clock::now), 1h),
                          _1,
                          30s);
  • 无直接的函数调用语义,需手动映射占位符(_1)到参数位置,类型无显式提示;
  • 陷阱 :直接传递steady_clock::now() + 1h会在bind创建时求值(而非调用 bind 对象时),需嵌套 bind 才能推迟求值;
  • 目标函数重载时,需手动将setAlarm强转为函数指针类型(否则编译失败),lambda 则天然支持重载决议。

性能对比:lambda 更高效

  • lambda 中调用目标函数是直接调用,编译器可正常做内联优化;
  • std::bind需传递函数指针 / 函数对象,编译器难以对 "通过函数指针的调用" 做内联,导致性能损耗。

表达力对比:lambda 显式,std::bind 依赖隐式规则

以 "判断值是否在区间内""创建 Widget 压缩函数对象" 为例:

  • lambda :捕获方式(值 / 引用)、参数传递方式(值 / 引用)显式可见,无需记忆额外规则:
c++ 复制代码
// 按值捕获lowVal/highVal,参数val按值传递(C++11)
auto betweenL = [lowVal, highVal](int val) {
    return lowVal <= val && val <= highVal;
};
  • std::bind :参数存储(默认值拷贝,需std::ref才是引用)、实参传递(完美转发,按引用传)依赖隐式规则,需记住 bind 的工作机制才能理解:
c++ 复制代码
auto betweenB = std::bind(std::logical_and<bool>(),
                          std::bind(std::less_equal<int>(), lowVal, _1),
                          std::bind(std::less_equal<int>(), _1, highVal));

std::bind 仅有的 C++11 适用场景(C++14 中被 lambda 替代)

仅在 C++11 的两个特殊场景下,std::bind有少量价值,C++14 中 lambda 的增强使其失去意义:

  • 场景 1:模拟移动捕获

    C++11 lambda 不支持移动捕获(如捕获std::unique_ptr),可结合 lambda+std::bind模拟;C++14 lambda 支持初始化捕获,无需此技巧。

  • 场景 2:绑定多态函数对象

    对带有模板化operator()的类(如PolyWidget),C++11 lambda 不支持auto形参,无法适配任意类型参数;而 bind 对象的operator()用完美转发,可接受任意类型实参;C++14 lambda 支持auto形参,可直接实现:

c++ 复制代码
// C++14 lambda替代std::bind绑定多态函数对象
auto boundPW = [pw](const auto& param) { pw(param); };

总结

  1. lambda 相比std::bind更易读、表达力更强,且因编译器内联优化更高效;
  2. std::bind仅在 C++11 中对 "模拟移动捕获""绑定多态函数对象" 有少量用途,C++14 中 lambda 可完全替代;
  3. std::bind存在参数求值时机、重载决议、隐式规则等陷阱,而 lambda 无此类问题。

原著在线阅读地址

相关推荐
zaizai100716 分钟前
【Effective Modern C++】学习第一章
c++
Fruiticecake40 分钟前
C 程序员速通现代 C++(一):lambda、std::function、移动语义与智能指针
c语言·c++
青少儿编程课堂1 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:中缀表达式求值解析
c++·python·算法·bfs·信息学竞赛
坤坤子吖4 小时前
Linux网络编程:TCP服务器的多进程与多线程实现
linux·服务器·开发语言·网络·c++·笔记·学习
一晌小贪欢4 小时前
Python基础:第 09 篇 · while 循环:重复直到不满足
开发语言·c++·python·数据可视化·面向对象·python办公
xiaoye-duck5 小时前
《C++ 项目:手写大模型接入 SDK》LLMManager架构设计与实现
开发语言·网络·c++·语言模型
一条大祥脚5 小时前
CuTe 与 CuTe DSL:从 C++ 模板元编程到 Python DSL 的 GPU 编程演进
开发语言·c++·python·cutlass·cute·cute dsl
·present·6 小时前
CSAPP(lecture 13_02 Linking)
c语言·c++
旖旎夜光6 小时前
【C++ 基础入门】C++ 多态(上):虚函数、重写、override/final 与抽象类
开发语言·c++·笔记·学习
青少儿编程课堂8 小时前
蓝桥杯青少组图形化 STEMA 省考(报名倒计时·11/22开考)+ 全国青少年信息素养大赛 2026—2027赛季 + 电子学会图形化考级:校园华容道大闯关
c++·python·算法·bfs·信息学竞赛