2

I want to pass a class method (bounded to an object) to a function in a library that asks for a non-const reference to a callable.

It would work perfectly fine with std::bind, if the parameter was not asked by reference. I don't know why it's asked by reference and i can't change it.

Is there a way to make the result of std::bind an lvalue ? Or should i rework everything ?

Here is a code that shows the problem:

#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;
}

the compilation command line and error:

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

/tmp/test.cpp:20:10: error: no matching member function for call to 'register_handler' agent_.register_handler(std::bind(&PersistentConnection::internal_handler, this, _1)); ~~~~~~~^~~~~~~~~~~~~~~~ /tmp/test.cpp:10:7: note: candidate function [with functor = std::_Bind)> (PersistentConnection *, std::_Placeholder<1>)>] not viable: expects an l-value for 1st argument void register_handler(functor & f) { ^ 1 error generated.

user368507
  • 1,388
  • 1
  • 13
  • 25
  • 2
    You could store it as a class member using a `std::function` to get an lvalue. – NathanOliver May 20 '16 at 19:03
  • Possible duplicate: http://stackoverflow.com/questions/7582546/using-generic-stdfunction-objects-with-member-functions-in-one-class –  May 20 '16 at 19:05
  • 1
    Does the library *store* the function object or does it just call it? If it stores it, can you update the question to indicate this? – Barry May 20 '16 at 19:20
  • Wait, `register_handler` takes by lvalue and just copies it? – Barry May 20 '16 at 20:06
  • @Barry full code of the lib: http://www.inspirel.com/yami4/files/yami4-gpl-1.10.1.tar.gz. File where to start: src/cpp/agent.h. Tell me what you think ! – user368507 May 20 '16 at 20:14
  • I'm not interested in the full code of the lib - I'm interested if `register_handler` copies the argument or stores the reference. – Barry May 20 '16 at 20:16
  • As i understand the code, it stores the reference. – user368507 May 20 '16 at 20:27

2 Answers2

2

If Agent holds stores the callable you pass in and requires an lvalue, instead of providing a member function, maybe you could just provide yourself?

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_;
};
Barry
  • 286,269
  • 29
  • 621
  • 977
  • Yes this could work, but i have two different methods to pass as handlers actually. (I agree my code snippet doesn't show it) – user368507 May 20 '16 at 19:52
0

You make lvalues from expressions by assigning them to a variable. That's what the term originally means - lvalues appear on the left side of the assignment operator. In this case, based on the name register_handler, the callable is presumably stored somewhere for later use, so a temporary or a local variable won't do it. You'll want to store it as a data member. The exact type of the bind expression is not known to you, and nonstatic data members cannot be auto in C++11, but you can use std::function!

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

std::function<void(std::string)> handler_;
JohannesD
  • 13,802
  • 1
  • 38
  • 30
  • And now you are in UB land as the agent refers to a destroyed object. – NathanOliver May 20 '16 at 19:10
  • Oops. Got confused by the fact that the mock code doesn't actually store the callable anywhere, but based on the name the original probably does. – JohannesD May 20 '16 at 19:13
  • indeed the original Agent::register_handler stores the callable – user368507 May 20 '16 at 19:18
  • There is no such thing `std::function<>` – Barry May 20 '16 at 19:22
  • @user368507 Edited to suggest an `std::function` data member instead. – JohannesD May 20 '16 at 19:22
  • @NathanOliver Though that depends on whether the agent actually stores a reference (or a pointer) as well instead of just taking a reference and copying the actual object. – JohannesD May 20 '16 at 19:29
  • @JohannesD Yes the function could do that but it shouldn't. If the function takes it by reference then you can normally assume it is going to keep that reference. If it was going to make a copy it would just take the callable by value. – NathanOliver May 20 '16 at 19:32