是否可以从 std::bind 对象访问参数?

Is it possible to access the arguments from an std::bind object?

请考虑以下场景。

一个假设的弹出菜单 class,显示一些操作,当其中一个被选中时,它将调用传入的操作,其形式为 std::function:

PopupMenu::PopupMenu(std::function<void(RowItem*)> editRowFunction, RowItem *item)
    : _editRowFunction(editRowFunction)
    , _item(item) {
}

然后在某个时候它可能会调用 execute:

PopupMenu::execute(} {
    _editRowFunction(_item);
}

然后我有另一个 class 那是一个 UI 对象:

class EditorWidget {
    void editRow(RowItem *row) {
        //edit the row
    }
}

下面是我如何使用它们:

int main() {
    auto item = new RowItem();
    auto editorWidget = new EditorWidget();
    PopupMenu menu(std::bind(&EditorWidget::editRow, editorWidget, item), item);
    menu.execute();
    return 0;
}

一切正常。我的问题如下: 如果我已经在 std::bind 中传递参数 item,为什么我必须再次将它作为第二个参数传递以便能够使用该参数调用绑定函数?如果我不这样做,并尝试从 PopupMenu::execute() 单独调用该函数,我会收到编译器错误。

另一种方法是使 PopupMenu 的构造函数像这样:

PopupMenu::PopupMenu(std::function<void()> editRowFunction)
    : _editRowFunction(editRowFunction) {}

如果我那样做,那么我会这样称呼它:

PopupMenu::execute() {
_editRowFunction();
}

我不喜欢这种方法的地方在于,我几乎可以在 PopupMenu 构造函数中传递任何绑定函数,并且它会被调用。但这不是我想要的,我只想强制执行具有特定签名的函数。

我也可以传递一个 lambda,是的。但是,让我们尝试在没有 lambda 的情况下解决它。 预先感谢大家的帮助。

std::bind(&EditorWidget::editRow, editorWidget, item)

std::bind 此处正在创建一个函数对象,该对象采用指向成员函数 EditorWidget::editRow 的指针,绑定到对象 editorWidget,使用参数 item。您所做的实际上是将参数固定到函数 EditorWidget::editRow 和参数 item。如此有效,您已经创建了一个不带参数的函数对象(因为您已经修复了它),并且 returns void.

PopupMenu 的构造函数实际上不需要具有类型为 RowItem* 的第二个参数。您可以像这样更改构造函数:

PopupMenu::PopupMenu(std::function<void()> editRowFunction)
    : _editRowFunction(editRowFunction)
{
}

然后像这样调用你的函数对象:

PopupMenu::execute(} {
    _editRowFunction();
}

在您当前的代码中,您传递给构造函数 PopupMenu 的函数对象未使用参数 _item。它满足编译器的要求,因为 _editRowFunctionstd::function<void(RowItem*)>.

类型

这里有一个简单的例子来说明问题:

#include <iostream>
#include <functional>

struct callable
{
    callable(std::function<void(std::string)> fn) : mFn(fn)
    {}

    std::function<void(std::string)> mFn;

    void Run() { mFn("world"); }
};

struct Foo {
    void print(std::string msg)
    {
        std::cout << msg << '\n';
    }
};

int main()
{
    Foo f;
    auto fn = std::bind(&Foo::print, &f, "hello");
    fn();

    callable c(fn);
    c.Run(); //expecting "world" to be printed
}

您可能希望输出为:

hello
world

但实际上是:

hello
hello

直播demo.

我能做的就是像这样更改函数对象的定义:

 auto fn = std::bind(&Foo::print, &f, std::placeholders::_1); //uses a placeholder

我得到了预期的输出。您可以做类似的事情,而不必对当前的实现做很多更改。