Effective Modern C++ 34. Prefer lambdas to std::bind

// typedef for a point in time
using Time = std::chrono::steady-clock::time_point;

enum class Sound { Beep, Siren, Whistle };

// typedef for a length of time
using Duration = std::chrono::steady_clock::duration;

// at time t, make sound s for duration d
void setAlarm(Time t, Sound s, Duration d);

I. lambda

// setSoundL("L" for "lambda") is a function object allowing a 
// sound to be specified for a 30-sec alarm to go off an hour 
// after it's set
auto setSoundL = [](Sound s) {
    // make std::chrono components available w/o qualification using namespace std::chrono;
    setAlarm(steady_clock::now() + hours(1), s, seconds(30));
};
// for C++ 14
auto setSoundL = [](Sound s) {
    using namespace std::chrono;
    using namespace std::literals;
    setAlarm(steady_clock::now() + 1h, s, 30s);
}

II. bind

using namespace std::chrono;
using namespace std::literals;
using namespace std::placeholders;
auto setSoundB = std::bind(setAlarm, steady_clock::now() + 1h, _1, 30s);

“steady_clock::now() + 1h” is passed as an argument to std::bind, not to setAlarm. That means that the expression will be evaluated when std::bind is called.

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

III. using lambdas generates faster code than using std::bind

setSoundL(Sound::Siren); // body of setAlarm may well be inlined here
setSoundB(Sound::Siren); // body of setAlarm is less likely to be inlined here

inside the call operator for setSoundB, the call to setAlarm takes place through a function pointer. Compiler are less likely to inline function calls through function pointers, and that means that calls to setAlarm through setSoundB are less likelty to be fully inlined than those through setSoundL.

IV. Compilers have no way to determine which of the two setAlarm function they should pass to std::bind

enum class Volum { Normal, Loud, LoudPlusPlus };
void setAlarm(Time t, Sound s, Duration d, Volum v);
auto setSoundL = [](Sound s) {
    using namespace std::chrono;
    setAlarm(steady_clock::now() + 1h, s, 30s);
};
// error! which setAlarm?
auto setSoundB = std::bind(setAlarm, std::bind(std::plus<>(), std::bind(steady_clock::now), 1h), _1, 30s);
// now okay
using SetAlarm3ParamType = void(*)(Time t, Sound s, Duration d);
auto setSoundB = 
std::bind(static_cast<SetAlarm3ParamType>(setAlarm),
    std::bind(std::plus<>(),
        std::bind(steady_clock::now), 1h), _1, 30s);
Widget w;
using namespace std::placeholders;
auto compressRateB = std::bind(compress, w, -1); // pass by value;
auto compressRateB = std::bind(comperess, std::ref(w), _1); // holds a reference to w

V. C++11 lambdas don’t offer move capture

std::vector<double>  data;
auto func = std::bind([](const std::vector<double>& data) { /* uses of data */ },std::move(data)) };

VI. bind an object with a templatized function call operator

class PolyWidget {
puclic:
    template<typename T>
    void operator() (const T& param) const;
};

PolyWidget pw;
auto boundPW = std::bind(pw, _1);
boundPW(1930);
boundPW(nullptr);
boundPW("Rosebud");
auto boundPW = [pw](const auto& param) { pw(param); }; // C++14
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值