1

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?

OverDrive
  • 27
  • 5
  • 2
    Side notes: (1) About `#include`: https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h, (2) About `using namespace std;`: https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice. – wohlstad Dec 14 '22 at 05:40
  • Regarding header files, why are you including ``? You don't use any Boost functionality. – Some programmer dude Dec 14 '22 at 05:41

2 Answers2

2

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.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • thanks, with using one more std::bind, it seems same to the lamda. [book content reference](https://i.stack.imgur.com/hgeuk.png) because the book say it equivalent to the lambda, I can't get the same result, so it makes me confused. – OverDrive Dec 14 '22 at 08:22
1
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.

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
  • Yes, in comparison, lambda is indeed much more convenient, I just want to test how to use bind to achieve the same functionality. – OverDrive Dec 14 '22 at 08:00
  • [book content reference](https://i.stack.imgur.com/hgeuk.png) I thought the book says it should be equivalent to the lambda? or I am wrong.. – OverDrive Dec 14 '22 at 08:16
  • @OverDrive The book made a mistake then, because the code snippet shown in that screenshot and in your question are *not* equivalent to a lambda that delays evaluation of the clock. – Silvio Mayolo Dec 14 '22 at 14:28