Использование std::bind в std::bind : ошибка компиляции (неявное приведение)

Когда я хочу создать std::function для обертывания члена work(..), у меня возникла ошибка компиляции, которая меня утомила.

образец кода :

class C{ 
public:
    C(){
        std::function<void(void) > f = std::bind(&C::work,
                                                 this,
                                                 std::bind(&C::step1, this),
                                                 std::bind(&C::step2, this));
        QList<decltype(f)> lst;
        lst.append(f);
        .....
    }
private:
    void work(std::function<bool()> fn1, std::function<bool()> fn2 ) {
        if (fn1()) {
            QTimer::singleShot(1, fn2);
        }
        else {
            QTimer::singleShot(5, fn1);
        }
    }

    bool step1(){return true;}
    bool step2(){return true;}
};

Ошибка компиляции:

main.cpp:49: erreur : conversion from 'std::_Bind_helper<false, void (C::*)(std::function<bool()>, std::function<bool()>), C* const, std::_Bind<std::_Mem_fn<bool (C::*)()>(C*)>, std::_Bind<std::_Mem_fn<bool (C::*)()>(C*)> >::type {aka std::_Bind<std::_Mem_fn<void (C::*)(std::function<bool()>, std::function<bool()>)>(C*, std::_Bind<std::_Mem_fn<bool (C::*)()>(C*)>, std::_Bind<std::_Mem_fn<bool (C::*)()>(C*)>)>}' to non-scalar type 'std::function<void()>' requested
                                              std::bind(&C::step2, this));
                                                                        ^

person Mohamed Hamzaoui    schedule 27.05.2016    source источник
comment
Bind of bind — это волшебство. Это не работает, как вы могли ожидать.   -  person Kerrek SB    schedule 27.05.2016
comment
Используйте лямбды вместо привязки.   -  person Yakk - Adam Nevraumont    schedule 27.05.2016
comment
Сообщение об ошибке вашего компилятора сообщает вам о проблеме, bind не выполняет неявное преобразование, а результатом bind(&C::step, this) является _Bind_helper не function<bool()>. Вам нужно сделать преобразование самостоятельно: bind(&C::work, this,function<bool()>(bind(&C::step1, this)), function<bool()>(bind(&C::step2, this))) Живой пример   -  person Jonathan Mee    schedule 27.05.2016
comment
@JonathanMee Это работает, но не по той причине, по которой вы думаете. std::bind(&C::step1, this), в конце концов, можно преобразовать в std::function<bool()>.   -  person Barry    schedule 27.05.2016
comment
когда мы тестируем с помощью function‹bool()›a=std::bind(&C::step1, this), function‹bool()›b=std::bind(&C::step2, this) и bind(&C: :work, this, a, b) мы получаем ту же проблему, поэтому я думаю, что это не проблема неявного преобразования   -  person Mohamed Hamzaoui    schedule 27.05.2016
comment
@Barry Конечно, это кабриолет. Я говорил, что код OP не работает, потому что bind не выполняет преобразование. Чтобы bind работало, программист должен выполнять преобразования явно. Или вы не согласны с этим утверждением?   -  person Jonathan Mee    schedule 27.05.2016
comment
@requinham Это абсолютно проблема. И написанный вами тестовый код работает нормально: ideone.com/tzifGe Возможно, проблема с компилятором или что-то еще. происходит то, что вы не показали мне.   -  person Jonathan Mee    schedule 27.05.2016
comment
@JonathanMee Да, это ложь. Смотрите мой ответ. Или связанный обман.   -  person Barry    schedule 27.05.2016
comment
@Barry И ты прав, я ошибаюсь, по норме +1. Спасибо, что поставили меня на место. Итак, причина, по которой моя работает, заключается в том, что я преобразовал ее, чтобы она больше не была bind-подвыражением. Это не имеет ничего общего с неявным преобразованием.   -  person Jonathan Mee    schedule 27.05.2016
comment
@JonathanMee Совершенно верно.   -  person Barry    schedule 27.05.2016
comment
@JonathanMee, ты прав.   -  person Mohamed Hamzaoui    schedule 27.05.2016
comment
По крайней мере, я могу быть прав насчет конечного результата, даже если @Barry исправит мою причину;)   -  person Jonathan Mee    schedule 27.05.2016


Ответы (1)


Проблема в том, что bind() охотно оценивает вложенные bind выражения. Таким образом, вместо того, чтобы получить какой-то вызываемый объект, который возвращает bool (как вы предполагали из std::bind(&C::step1, this)), вы просто получите bool.

Вместо этого используйте лямбды:

std::function<void(void) > f = [this]{
    work([this]{ return step1(); },
         [this]{ return step2(); });
};
person Barry    schedule 27.05.2016
comment
Мне было интересно, знаете ли вы, где упоминается эта проблема. +1 - person Mohamad Elghawi; 27.05.2016
comment
@MohamadElghavi Что ты имеешь в виду? - person Barry; 27.05.2016
comment
Вы сказали: bind() будет охотно оценивать вложенные выражения связывания. Просто интересно, где вы это прочитали. Заранее спасибо. - person Mohamad Elghawi; 27.05.2016
comment
@Mohamad ссылка, см. поведение в разделе operator() - person Barry; 27.05.2016
comment
@MohamadElghawi (например, другое подвыражение привязки использовалось в качестве аргумента при первоначальном вызове привязки), затем это подвыражение привязки вызывается немедленно как объект lvalue с теми же cv-квалификациями, что и у g, и его результат передается в вызываемый объект. en.cppreference.com/w/cpp/utility/functional/ - person Jonathan Mee; 27.05.2016