I read the item34: prefer lambdas to std::bind of "modern effective C ", it says
Fixing the problem requires telling std::bind to defer evaluation of the expression until setAlarm is called, and the way to do that is to nest a second call to std::bind inside the first one:
so I wrtie the following code to test
#include <bits/stdc .h>
#include <boost/type_index.hpp>
#include <memory>
using namespace std;
using Time = std::chrono::steady_clock::time_point;
enum class Sound
{
Beep,
Siren,
Whistle
};
using Duration = std::chrono::steady_clock::duration;
template <typename T>
std::underlying_type_t<T> printEnum(T const value)
{
return static_cast<std::underlying_type_t<T>>(value);
}
void setAlarm(Time t, Sound s, Duration d)
{
cout << "time:" << t.time_since_epoch().count() << " ring"
<< " duraion:" << (std::chrono::duration_cast<std::chrono::seconds>(d)).count()
<< " sound:" << static_cast<typename std::underlying_type<Sound>::type>(s)
<< " sound:" << printEnum(s)
<< endl;
}
int main()
{
using namespace std::chrono;
using namespace std::literals;
using namespace std::placeholders;
auto setSoundB = std::bind(setAlarm,
std::bind(std::plus<>(), steady_clock::now(), 1h), _1, seconds(30));
cout << "function calc time:" << steady_clock::now().time_since_epoch().count() << endl;
setSoundB(Sound::Beep);
cout << "function calc time:" << steady_clock::now().time_since_epoch().count() << endl;
setSoundB(Sound::Beep);
return 0;
}
but I get the following result:
function calc time:1670995052139460000
time:1670998652139145000 ring duraion:30 sound:0 sound:0
function calc time:1670995052139480000
time:1670998652139145000 ring duraion:30 sound:0 sound:0
why the time is same, it seems that the expression still evaluated when std::bind is called?
CodePudding user response:
std::bind(setAlarm, std::bind(std::plus<>(), steady_clock::now(), 1h), _1, seconds(30))
This doesn't delay evaluation of the steady_clock::now
. You still need to delay the evaluation of that function, not call it immediately.
std::bind(setAlarm,
std::bind(std::plus<>(), std::bind(steady_clock::now), 1h),
_1,
seconds(30))
Compare that to the much more readable
[](Sound sound) { setAlarm(steady_clock::now() 1h, sound, seconds(30)); }
That's the point the C guideline is trying to make.
CodePudding user response:
std::bind
copies the arguments.
steady_clock::now()
will only be called once, when you do the binding.
You need to nest steady_clock::now()
itself with its own separate binding:
auto setSoundB = std::bind(setAlarm,
std::bind(std::plus<>(),
std::bind(&steady_clock::now),
1h),
_1, seconds(30));
While the two-bind version is a little too much, the three-bind version makes it very clear why lambdas are preferable.