Home > OS >  a question of std::bind expression evaluating
a question of std::bind expression evaluating

Time:12-14

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.

  • Related