boost::bind() связывает дополнительные аргументы?

Связывает ли привязка boost::bind() дополнительные аргументы, поскольку кажется, что передача функции привязки без аргументов в одну, ожидающую двойного аргумента, работает нормально? Если бы я явно написал функцию связывания, что бы это было?

struct MyClass
{
    void f() 
    {
        std::cout << "f()" << std::endl;
    }
};

void bar( const boost::function<void(const double&)>& f )
{
    f( 1.0 );
}

int main()
{
    MyClass c;

    // why this compiles
    bar( boost::bind( &MyClass::f, &c ) );

    // what should I write if I want to create the binded function explicitly before pass into bar?
    // boost::function<void(const double&)> f = boost::bind( ... boost::bind( &MyClass::f, &c ), ?? )
    bar( f );

}

person surfcode    schedule 27.03.2014    source источник


Ответы (1)


Так задумано, несвязанные параметры (например, 1.0), передаваемые при вызове выражения привязки, просто игнорируются.

boost::function<void(const double&)> f = boost::bind(&MyClass::f, &c);
bar(f);

подойдет для явного назначения выражения привязки.

Обновите комментарий:

Помните, два правила:

  • function<...> имеет фиксированную подпись
  • bind выражения не имеют фиксированную подпись. Вся цель bind состоит в том, чтобы изменить подпись. Это включает, например.

    • adding state to fill in for formal parameters dropped from the signature or
    • добавление параметров, которые следует игнорировать, не привязывая их к целевому вызываемому объекту
    • изменение типа аргумента/возврата с помощью неявных преобразований
    • даже изменение порядка, в котором параметры привязываются к целевому вызываемому объекту, в то время как сигнатура технически может оставаться неизменной.

Таким образом, хотя вы не можете назначать друг другу разные func<...> типы, вы всегда можете bind bind присвоить одну подпись другой.

Вот более полная демонстрация, показывающая пределы того, что вы можете делать с function и bind, и почему (как они себя ведут): Прямой эфир на Coliru:

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <cassert>

int foo0()            { return 0; }
int foo1(int)         { return 1; }
int foo2(int,int)     { return 2; }
int foo3(int,int,int) { return 3; }

int main()
{
    boost::function<int()>            func0;
    boost::function<int(int)>         func1;
    boost::function<int(int,int)>     func2;
    boost::function<int(int,int,int)> func3;

    // "straight" assignment ok:
    // -------------------------
    func0 = foo0;                          assert (0 == func0());
    func1 = foo1;                          assert (1 == func1(-1));
    func2 = foo2;                          assert (2 == func2(-1,-1));
    func3 = foo3;                          assert (3 == func3(-1,-1,-1));

    // "mixed" assignment not ok:
    // --------------------------
    // func0 = foo1;                       // compile error
    // func3 = foo2;                       // compile error
    // func1 = func2;                      // compile error, just the same
    // func2 = func1;                      // compile error, just the same

    // SOLUTION: you can always rebind:
    // --------------------------------
    func0 = boost::bind(foo3, 1, 2, 3);    assert (func0() == 3);
    func3 = boost::bind(foo1, _3);         assert (func3(-1,-1,-1) == 1);
    func3 = boost::bind(foo2, _3, _2);     assert (func3(-1,-1,-1) == 2);
    // same arity, reversed arguments:
    func3 = boost::bind(foo3, _3, _2, _1); assert (func3(-1,-1,-1) == 3);

    // can't bind more than number of formal parameters in signature:
    // --------------------------------------------------------------
    // func3 = boost::bind(foo1, _4);      // in fact, the bind is fine, but assigning to `func3` fails
}

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

Ваше здоровье

person sehe    schedule 27.03.2014
comment
@seha - где лишний аргумент? MyClass::f имеет 0 аргументов. Когда boost::bind(&MyClass::f, &c) назначается в boost::function‹void(const double&)›, связывает ли это еще один дополнительный аргумент типа double вокруг него внутри boost::function assign?? - person surfcode; 27.03.2014
comment
@Surfcode, MyClass::f имеет один аргумент (this), который вы привязали к &c в выражении привязки. Теперь в bar (и через экземпляр boost::function<>) вы передаете дополнительный аргумент (1.0, как я уже упоминал), который не был связан и поэтому игнорируется. - person sehe; 27.03.2014
comment
извините за отложенный вопрос: вместо адаптировать = привязать (& бар, _1, _3); как мне это сделать: function‹int(int,int)› adapt2 = bind(&bar, _1, _3); // адаптировать = адаптировать2 ?? поскольку я хотел бы обойти адаптацию2 (как тип аргумента), прежде чем я смогу назначить адаптацию. Таким образом, нельзя назначить bind(...) для прямой адаптации. - person surfcode; 27.03.2014
comment
@surfcode Я переписал объяснение, отвечающее на ваш вопрос. Читайте медленно. Я думаю, пенни упадет. Есть более обширный образец, демонстрирующий, что работает, а что нет, почему и как оно себя ведет. Ваше здоровье. - person sehe; 27.03.2014