条款34:优先选用lambda式,而非std::bind

std::bind返回的函数对象为绑定对象。考虑在程序的某处我们想要设置在一小时后发出警报并持续30秒,考虑如下代码:

using Time = std::chrono::steady_clock::time_point;

enum class Sound {Beep, Siren, Whistle};

using Duration = std::chrono::steady_clock::duration;
// 在时刻t,发出声音s,持续时常d
void setAlarm(Time t, Sound s, Duration d); 
// 接受一个指定声音,该声音将在1小时后发出,并持续30秒 
auto setSoundL = 
	[] (Sound s)
	{
		using namespace std::chrono;
		setAlarm(steady_clock::now() + hours(1), s, seconds(30));
	;

然后我们撰写对应的std::bind的版本

auto setSoundB =
	std::bind(setAlarm,
			  steady_clock::now() + 1h, // 错误!见下文
			  _1,
			  30s);

steady_clock::now() + 1h作为实参被传递给了std::bind,而非setAlarm。意味着表达式在评估求值时候是在调用std::bind时刻。最终导致的结果是,警报设定的启动时刻是在调用std::bind的时刻之后的一个小时,而非setAlarm的时候的一个小时。解决办法是在原来的std::bind里嵌套第2层std::bind调用:

auto setSoundB = 
	std::bind(setAlarm,
			  std::bind(std::plus<>(), steady_clock::now(), 1h),
			  _1,
			  30s);

一旦对setAlarm实施了重载,会产生新的问题:

enum class Volum {Normal, Loud, LoudPlusPlus };
void setAlarm(Time t, Sound s, Duration d, Volume v);

之前的lambda式会一如既往运作,但是对于std::bind的调用,无法通过编译了

auto setSoundB = 
	std::bind(setAlarm,
			  std::bind(std::plus<>(), steady_clock::now(), 1h),
			  _1,
			  30s);

因为编译器无法确定应该將哪个setAlarm版本传递给std::bind。它拿到的所有信息就只有一个函数名,而仅有函数名本身是多义的。解决办法是setAlarm必须强制转型到适当的函数指针类型:

using SetAlarm3ParamType = void(*)(Time t,Sound s, Duration d);
auto setSoundB = 
	std::bind(static_cast<SetAlarm3ParamType>(setAlarm),
			  std::bind(std::plus<>(), steady_clock::now(), 1h),
			  _1,
			  30s);

C++11std::bind仅在两个受限的场合有着使用的理由:

  1. 移动捕获
  2. 多态函数对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值