0

Most examples don't clearly show how to create a std::function with a static class method that takes an object instance as the first parameter.

I would like to take a static class method that takes an object instance as the first parameter and create a new function that can be used as a C-style callback function and has access to an object instance.

I seem to have tried everything. I took the example here and tried to refactor it to my use case with no luck by using a similar examples here.

See more up-to-date example below

#include <functional>
#include <iostream>

struct Foo
{
    Foo(int me) : m_me(me) {}

    static int foo_static(Foo* f, int a, int b) { return f->m_me + a + b; }
    int m_me;
};

int main()
{
    Foo f(4);

    using std::placeholders::_1;
    std::function<int(int,int)> new_func = std::bind(&Foo::foo_static, &f, _1);

    std::cout << new_func(3, 4) << std::endl;
}

EDIT

Forgot compiler output

$ c++ main.cpp -std=c++14
main.cpp:25:30: error: no viable conversion from '__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>' to
      'std::function<int (int, int)>'
        std::function<int(int,int)> new_funct = std::bind(&Foo::foo_static, &f, _1);
                                    ^           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1627:5: note: candidate constructor not
      viable: no known conversion from '__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>' to 'std::nullptr_t'
      (aka 'nullptr_t') for 1st argument
    function(nullptr_t) _NOEXCEPT : __f_(0) {}
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1628:5: note: candidate constructor not
      viable: no known conversion from '__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>' to
      'const std::__1::function<int (int, int)> &' for 1st argument
    function(const function&);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1629:5: note: candidate constructor not
      viable: no known conversion from '__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>' to
      'std::__1::function<int (int, int)> &&' for 1st argument
    function(function&&) _NOEXCEPT;
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1631:5: note: candidate template
      ignored: requirement '__callable<__bind<int (*)(Foo *, int, int), Foo *, const __ph<1> &> >::value' was not satisfied [with _Fp =
      std::__1::__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>]
    function(_Fp);
    ^
1 error generated.

Here's a bit more detail on what I'm trying to accomplish. The m_callback is what I'm trying to setup. I could push what I need in the callback into the ClientData but I like the Command structure to hold on to it's data and not have to create a new structure to pass as the ClientData per command.

#include <functional>
#include <iostream>
#include <string>

typedef void (* callback) (Client* client, ClientData* client_data);

struct Command
{
    int execute() = 0;
}

struct Search : Command
{
    enum SearchType { kType1, kType2 };

    Search(Logger log, std::string query, SearchType type) : m_log(log), m_callback(), m_query(query), m_typ(type)
    {
        m_callback = // create callback
    }

    int execute(Client* client, ClientData* client_data)
    {
        client->query(client_data, m_callback, m_query, m_type);
    }

    static int my_callback(Foo* f, Client* client, ClientData* client_data);

    Logger& m_log;
    callback m_callback;
    std::string m_query;
    SearchType m_type;
    // other data I want in the callback that isn't passed in client_data
};

int main()
{
    Logger log;
    Search search(log, "some search", Search::kType1);
    Client client;
    ClientData client_data;

    search.execute(&client, client_data);
}

So I figured out what I was doing wrong with the std::bind but now I need to convert that to the C-style callback I need to work with.

minnymauer
  • 374
  • 1
  • 4
  • 17
  • 2
    What's wrong with using a lambda funtion instead of a clumsy bind call? – πάντα ῥεῖ May 10 '19 at 19:47
  • 1
    Why is `foo_static` static if it needs `Foo` instance? Smells like a member function. – Quimby May 10 '19 at 19:49
  • @πάνταῥεῖ Looks like nothing https://stackoverflow.com/questions/17363003/why-use-stdbind-over-lambdas-in-c14 – minnymauer May 10 '19 at 19:51
  • 1
    Using a lambda is easier, but you probably also want to check out pointers to member functions: https://stackoverflow.com/questions/2402579/function-pointer-to-member-function – user268396 May 10 '19 at 19:51
  • @Quimby I thought I originally read that member functions couldn't be used as C-style callbacks. Is that untrue? – minnymauer May 10 '19 at 19:52
  • @rangeme: yes, it is. If that is all you want, just make it a proper member function and use a pointer to member function for your callback. You still have to make sure the object is still in scope (live) when the callback gets invoked, of course. – user268396 May 10 '19 at 19:55
  • 1
    @rangeme c-style means function pointer? In that case no, the can't but neither can `std::function`. If you show why would you like that perhaps someone can recommend the best c++ solution to it. – Quimby May 10 '19 at 20:04
  • @Quimby You're right. Let me add more data on my use case. – minnymauer May 10 '19 at 20:21

1 Answers1

1

The bind function has something wrong, you have used _1 only however you need to pass 2 arguments.

Change this:

using std::placeholders::_1;
std::function<int(int,int)> new_func = std::bind(&Foo::foo_static, &f, _1);

To

using std::placeholders::_1;
using std::placeholders::_2;
std::function<int(int,int)> new_func = std::bind(&Foo::foo_static, &f, _1,_2);