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

问题描述

请考虑以下情况。

一个假想弹出菜单类显示器的一些动作,并且当选择它们中的一个,它会调用在这在表单动作传递的std::function

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

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

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

然后我有了另一个类,它是一个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;
}

一切正常。我的问题如下: 如果我已经在item中传递了参数std::bind,为什么必须再次将其作为第二个参数传递,以便能够使用该参数调用绑定函数?如果没有,尝试从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。因此,有效地创建了一个不带参数的函数对象(因为已将其固定),并返回void

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

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

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

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

在当前代码中,传递给构造函数_item的函数对象未使用参数PopupMenu。由于_editRowFunction的类型为std::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,std::placeholders::_1); //uses a placeholder

,我得到了预期的输出。您可以执行类似的操作,而不必对当前的实现进行很多更改。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...