【问题标题】:C++ how to pass class method to a function that asks a reference to callableC ++如何将类方法传递给要求对可调用对象的引用的函数
【发布时间】:2016-05-20 18:59:36
【问题描述】:

我想将类方法(绑定到对象)传递给库中的函数,该函数要求对可调用对象进行非常量引用。

如果参数不是通过引用询问的,它可以与 std::bind 完美配合。我不知道为什么它是通过引用询问的,我无法更改它。

有没有办法使 std::bind 的结果成为左值?还是我应该重做所有东西?

这是显示问题的代码:

#include <iostream>
#include <functional>
#include <string>
using namespace std::placeholders;

// code in a lib that i cannot change
class Agent {
public:
        template <typename functor>
        void register_handler(functor & f) {
            // f is stored in data member "functor & f_;" of connection_event_generic_dispatcher in initializer list of ctor.
            std::auto_ptr<details::connection_event_dispatcher_base> monitor(new details::connection_event_generic_dispatcher<functor>(f));

            pimpl_base_->register_connection_event_monitor(monitor);
        }
};

// code i can edit
class PersistentConnection {
public:
        PersistentConnection(): data_member_("world") {
                agent_.register_handler(std::bind(&PersistentConnection::internal_handler, this, _1));
        }

private:
        void internal_handler(std::string message) {
                std::cout << message << " " << data_member_ << std::endl;
        }

        std::string data_member_;
        Agent agent_;
};

int main (int argc, char** argv) {
        PersistentConnection p;
        return 0;
}

编译命令行和错误:

clang++ --std=c++11 /tmp/test.cpp -o /tmp/test

/tmp/test.cpp:20:10: 错误: 没有匹配的成员函数来调用 'register_handler' agent_.register_handler(std::bind(&PersistentConnection::internal_handler, 这个,_1)); ~~~~~~~^~~~~~~~~~~~~~~~ /tmp/test.cpp:10:7: 注意:候选函数 [with functor = std::_Bind)> (PersistentConnection *, std::_Placeholder)>] 不是 可行的:期望第一个参数的 l 值 无效寄存器处理程序(函子和 f){ ^ 产生 1 个错误。

【问题讨论】:

  • 您可以使用std::function 将其存储为类成员以获取左值。
  • 库是存储函数对象还是只是调用它?如果它存储它,您可以更新问题以表明这一点吗?
  • 等等,register_handler 通过左值获取并复制它?
  • @Barry 库的完整代码:inspirel.com/yami4/files/yami4-gpl-1.10.1.tar.gz。文件从哪里开始:src/cpp/agent.h。告诉我你的想法!

标签: c++ c++11


【解决方案1】:

如果Agentholds存储了你传入的callable并且需要一个左值,而不是提供一个成员函数,也许你可以自己提供?

class PersistentConnection {
public:
    PersistentConnection(): data_member_("world") {
        agent_.register_handler(*this);
    }

    void operator()(std::srting message) {
        std::cout << message << " " << data_member_ << std::endl;
    }

    std::string data_member_;
    Agent agent_;
};

【讨论】:

  • 是的,这可以工作,但实际上我有两种不同的方法可以作为处理程序传递。 (我同意我的代码 sn-p 没有显示)
【解决方案2】:

您通过将表达式分配给变量来从表达式中生成左值。这就是该术语最初的含义 - l 值出现在赋值运算符的 left 侧。在这种情况下,基于名称register_handler,可调用对象可能存储在某处以供以后使用,因此临时变量或局部变量不会这样做。您需要将其存储为数据成员。 bind 表达式的确切类型您不知道,非静态数据成员在 C++11 中不能是 auto,但您可以使用std::function!

PersistentConnection(): 
    data_member_("world"),
    handler_(std::bind(&PersistentConnection::internal_handler, this, _1))
{
    agent_.register_handler(handler);
}

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

【讨论】:

  • 现在你在 UB 领域,因为代理指的是一个被破坏的对象。
  • 糟糕。对模拟代码实际上并未将可调用对象存储在任何地方这一事实感到困惑,而是基于原始代码可能存储的名称。
  • 确实原来的 Agent::register_handler 存储了可调用对象
  • 不存在std::function&lt;&gt;
  • @user368507 编辑建议使用std::function 数据成员。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-07
  • 2015-04-20
  • 1970-01-01
  • 2015-02-01
  • 1970-01-01
  • 2013-08-23
  • 1970-01-01
相关资源
最近更新 更多