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.

8
  • 2
    What's wrong with using a lambda funtion instead of a clumsy bind call? Commented May 10, 2019 at 19:47
  • 1
    Why is foo_static static if it needs Foo instance? Smells like a member function. Commented May 10, 2019 at 19:49
  • @πάνταῥεῖ Looks like nothing stackoverflow.com/questions/17363003/… Commented May 10, 2019 at 19:51
  • 1
    Using a lambda is easier, but you probably also want to check out pointers to member functions: stackoverflow.com/questions/2402579/… Commented May 10, 2019 at 19:51
  • 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. Commented May 10, 2019 at 20:04

1 Answer 1

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);
Sign up to request clarification or add additional context in comments.

3 Comments

That's it, thank you. Why do you need to pass 2 arguments?
The static function needs 3 arguments (Foo *, int a, int b). The first argument is introduced while creating the function (&f) .. the other 2 will be passed later at the time of the function call new_func(3,4)
Ah ok, I was understanding the placeholders incorrectly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.