1

Note: The following applies equally to Boost.Thread and C++11 threads.

I have a condition variable which condition is actually a simple boolean variable.

// assume these are global
mutex m;
condition_variable c;
boolean b = false;

I wanted to use the wait(lock, predicate) syntax. I could use for example a lambda:

c.wait(lock, [] () { return b; });

But I supposed there should be a more idiomatic way to wrap a variable as a callable. So I found out that reference_wrapper provides an operator() that retrieves the wrapped value. Therefore I tried:

c.wait(lock, cref(b));

But g++ (4.9.1) does not compile it, arguing no matching function for call to '(boost::reference_wrapper<const bool>) ()' (if I use std::ref the error is somewhat different, but still not compiling).

Shouldn't a reference_wrapper qualify as a proper predicate for a condition variable? If not, why? And what would be the right wrapper for b in this case?

EDIT: So @Praetorian has explained quite right my mistake, but, is there really nothing like this on Boost or the standard (there may be mistakes here):

template<typename T>
struct as_callable {
    T &objref;
    as_callable(T &r) : objref(r) {}
    T &operator()() {
        return objref;
    }
};
jdehesa
  • 58,456
  • 7
  • 77
  • 121
  • `std::ref` returns a reference wrapper. Boost Phoenix `ref` returns a _functor_. I suppose you might have confused the two (see my answer) – sehe Sep 15 '14 at 20:35
  • 1
    `while (!b) { c.wait(lock); }` is a bit more readable than `c.wait(lock, []{ return b; });`, and semantically identical. The lambda gets nastier when `b` is a local (`c.wait(lock, [&]{ return b; });`) or member variable (`c.wait(lock, [this]{ return b; });`) that requires capture, but the explicit version stays the same. – Casey Sep 16 '14 at 19:59

2 Answers2

1

std::reference_wrapper::operator() is only available when the reference_wrapper is storing a callable, which a plain bool isn't. Use a lamdba for the predicate.

Also consider using std::atomic_bool instead of a plain bool if that boolean is being modified in a different thread from the one where your condition variable is waiting on it.


If you really want to use a wrapper instead of a lambda you could write a trivial wrapper class that overloads operator() and returns the stored boolean value when invoked.

struct bool_wrapper
{
    bool_wrapper(bool& b) : b_(&b) {}
    bool *b_;

    bool operator()() const noexcept { return *b_; }
};

Now you can use this class to wrap the boolean and pass it to condition_variable::wait as

c.wait(lock, bool_wrapper(b));

Live demo

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • Ok, I understand. I have extended the question now (I'll mark yours as right if there is not such thing). I shouldn't need `std::atomic_bool` if accesses to `b` are protected with locks, right? – jdehesa Sep 15 '14 at 18:48
  • @javidcf `reference_wrapper` does define an implicit conversion operator to `T&`, but the problem here is that `condition_variable::wait` expects a nullary predicate that returns `bool`, so it's going to try and invoke whatever you pass to it as if it were a callable. What you're asking for is a wrapper that stores a `T` and provides an `operator()` that simply returns that same `T`. I don't know of any such wrapper, and it doesn't sound very useful, does it? You can write one yourself. If you're protecting access to the boolean via mutex locks you shouldn't need an `atomic_bool`. – Praetorian Sep 15 '14 at 19:06
  • @javidcf Added an example, but if I were you, I'd use a lambda. – Praetorian Sep 15 '14 at 19:18
  • Ok thanks, I understand. It's not like I hate lambdas or anything, but I was curious about whether there was something already covering it in the standard. – jdehesa Sep 15 '14 at 19:20
1

In addition to the other answer, which aptly explains what went wrong, I think I might be able to explain how you came to the wrong expectation.

Lo and behold, there's also Boost Phoenix's version of ref() and cref() which, surprisingly make the reference available as a Phoenix Lazy Actor. That is: phx::ref() and phx::cref() are functors!

This means you could simply use

c.wait(lock, phx::cref(b));

as you might have encountered it somewhere in the past.

sehe
  • 374,641
  • 47
  • 450
  • 633