您的位置:首页 > 编程语言 > C语言/C++

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

2018-01-26 11:01 351 查看
// 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
4000
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐