Использование reference_wrapper в качестве предиката condition_variable

Примечание: следующее относится в равной степени к потокам Boost.Thread и C ++ 11.

У меня есть переменная условия, условие которой на самом деле является простой логической переменной.

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

Я хотел использовать wait(lock, predicate) синтаксис. Я мог бы использовать, например, лямбду:

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

Но я предположил, что должен быть более идиоматичный способ обернуть переменную как вызываемую. Итак, я узнал, что reference_wrapper обеспечивает operator() который возвращает упакованное значение. Поэтому я попытался:

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

Но g ++ (4.9.1) не компилирует его, утверждая no matching function for call to '(boost::reference_wrapper<const bool>) ()' (если я использую std::ref ошибка несколько иная, но все равно не компилируется).

Не должен reference_wrapper квалифицироваться как правильный предикат для условной переменной? Если нет, то почему? И что было бы правильным оберткой для b в этом случае?

РЕДАКТИРОВАТЬ: Таким образом, @Praetorian совершенно правильно объяснил мою ошибку, но разве нет ничего подобного в Boost или стандарте (здесь могут быть ошибки):

template<typename T>
struct as_callable {
T &objref;
as_callable(T &r) : objref(r) {}
T &operator()() {
return objref;
}
};

1

Решение

std::reference_wrapper::operator() доступно только когда reference_wrapper хранит подлежащий выкупу, какая равнина bool нет. Используйте lamdba для предиката.

Также рассмотрите возможность использования std::atomic_bool вместо равнины bool если это логическое значение изменяется в потоке, отличном от того, в котором ваша условная переменная ожидает его.


Если вы действительно хотите использовать оболочку вместо лямбды, вы можете написать тривиальный класс-оболочку, который перегружает operator() и возвращает сохраненное логическое значение при вызове.

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

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

Теперь вы можете использовать этот класс, чтобы обернуть логическое значение и передать его condition_variable::wait как

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

Живая демо

1

Другие решения

В дополнение к другому ответу, который точно объясняет, что пошло не так, я думаю, что я мог бы объяснить как Вы пришли к неверному ожиданию.

И вот, есть также версия Boost Phoenix’s ref() а также cref() что, на удивление, делает ссылку доступной в роли ленивого актера Феникса. То есть: phx::ref() а также phx::cref() являются функторы!

Это означает, что вы можете просто использовать

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

как вы могли встретить это где-то в прошлом.

1

По вопросам рекламы [email protected]