Примечание: следующее относится в равной степени к потокам 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;
}
};
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));
В дополнение к другому ответу, который точно объясняет, что пошло не так, я думаю, что я мог бы объяснить как Вы пришли к неверному ожиданию.
И вот, есть также версия Boost Phoenix’s ref()
а также cref()
что, на удивление, делает ссылку доступной в роли ленивого актера Феникса. То есть: phx::ref()
а также phx::cref()
являются функторы!
Это означает, что вы можете просто использовать
c.wait(lock, phx::cref(b));
как вы могли встретить это где-то в прошлом.