7

I have api function f_api(std::function<void(int)> func) and now I have my process class

class Func {
public:
    void operator()(int i) {
        // do some work
    }
    int operator()(int i, int j) {
        // do some other work
    }
};

and I want use Func f f(int i) to pass to f_api to do the work; so I use std::bind

Func f;
std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
f_api(func);

but HERE the problem, How can I indicate which Func::operator()() I want to bind? I can give a member function by its name, but how can I process this when this member function do have several different signed reloading functions? Will std::bind find me the most suitable function to be called? C++ is so complicated.....

the minimal verifiable case:

#include <iostream>
#include <functional>

using namespace std;

class Func {
public:
    void operator()(int i) {
        // do some work
        cout << "i is: " << i << endl;
    }
    int operator()(int i, int j) {
        // do some other work
    }
};

void f_api(function<void(int)> f) {
    f(3);
}

int main () {
    Func f;
    std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
    f_api(func);
    return 0;
}

the compiling error:

a.cpp: In function ‘int main()’:
a.cpp:23:91: error: no matching function for call to ‘bind(<unresolved overloaded function type>, Func*, const std::_Placeholder<1>&)’
     std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
                                                                                           ^
a.cpp:23:91: note: candidates are:
In file included from a.cpp:2:0:
/usr/include/c++/4.8/functional:1655:5: note: template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__or_<std::is_integral<typename std::decay<_Tp>::type>, std::is_enum<typename std::decay<_Tp>::type> >::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^
/usr/include/c++/4.8/functional:1655:5: note:   template argument deduction/substitution failed:
a.cpp:23:91: note:   couldn't deduce template parameter ‘_Func’
     std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
                                                                                           ^
In file included from a.cpp:2:0:
/usr/include/c++/4.8/functional:1682:5: note: template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^
/usr/include/c++/4.8/functional:1682:5: note:   template argument deduction/substitution failed:
a.cpp:23:91: note:   couldn't deduce template parameter ‘_Result’
     std::function<void(int)> func = std::bind(&Func::operator(), &f, std::placeholders::_1);
                                                                                           ^

And in my case it's a little bit different cause my class Func cannot be assigned cause one member field of that class is not assignable, so I will get a slightly different error during the compiling time.

Liu Weibo
  • 405
  • 4
  • 12
  • Have you *tried* it? Do you get any errors, or does it work as expected? – Some programmer dude Aug 03 '17 at 11:03
  • 4
    I would advice you to forget that std::bind even exists. Almost always a lambda is easier to understand. – kay Aug 03 '17 at 11:05
  • Yes, I do have. when I do the `f_api(func)`. it shows me the error about function objects assignment incompatible or so – Liu Weibo Aug 03 '17 at 11:06
  • @kay if he's limited to C++11 or 0x then he must have preference to lambda's in certain cases. Plus implementation of some compilers prompt bind usage. Eg. ANY Microsoft compiler after 2012. – Swift - Friday Pie Aug 03 '17 at 11:08
  • That is very relevant information and should be included in the question body (together with the errors). Please [read about how to ask good questions](http://stackoverflow.com/help/how-to-ask), and learn how to create a [Minimal, **Complete**, and Verifiable Example](http://stackoverflow.com/help/mcve) if you haven't done it yet. – Some programmer dude Aug 03 '17 at 11:08
  • @kay You can't pass a lambda with capture as a pointer or something, I can't determine which function or how many function will be called, cause I am writing a library here, and I am the endpoint of the code chains – Liu Weibo Aug 03 '17 at 11:11
  • 2
    @LiuWeibo - You can't easily pass a pointer to the result of `bind` either. Furthermore, a captureless lambda can be cast to a regular function pointer. The result of `std::bind` isn't guaranteed to be castable in such a way IIRC. – StoryTeller - Unslander Monica Aug 03 '17 at 11:16
  • @Someprogrammerdude At your command, sir – Liu Weibo Aug 03 '17 at 11:28
  • Please mark and answer with the green check. – Jive Dadson Dec 26 '17 at 20:42

2 Answers2

16

You can do it the nasty long way for all overloads. By casting:

using sig1 = void (Func::*)(int);
using sig2 = void (Func::*)(int, int);

std::bind(static_cast<sig1>(&Func::operator()), &f, std::placeholders::_1);

Alternatively, you could recognize the std::bind isn't all that useful if you have lambdas:

std::function<void(int)> func = [&](int i) { f(i); };
StoryTeller - Unslander Monica
  • 148,497
  • 21
  • 320
  • 399
  • was discussed here https://stackoverflow.com/questions/17363003/why-use-stdbind-over-lambdas-in-c14 Problem is that most popular compilers do not implement lambda's effectively and C++14 isn't supported much. – Swift - Friday Pie Aug 03 '17 at 11:10
  • 2
    @Swift - It's been several years since that post. Compiler support steadily became better. Even MSVC has decent support (and that's saying something). – StoryTeller - Unslander Monica Aug 03 '17 at 11:12
  • @StoryTeller it became better, but not decent. Last decent version is 2012, later ones actually are banned from use by the concern I work for, though test are going on constantly, for each version. working constantly with those, we accumulated about three hundred of use cases where MSVC generated outright wrong code. some of those you can find on SO. Last versions still support only partial c++11; c++14 ones at whim may fail, lamba code is supported in limited way (that scary "please simplify your code"message). Standards do exist but in real life not everything is allowed to be used. – Swift - Friday Pie Aug 04 '17 at 11:59
  • @Swift - My condolences for using MSVC at all. Lambdas aside, Microsoft do support the features *they* proposed well enough. And in case you think I get to use all these shiny toys at work, I'll have you know I'm still programming in C++03 for my living. The latest and greatest is personal interest. – StoryTeller - Unslander Monica Aug 04 '17 at 12:23
10

Func is a function object. Rather than taking the member-function pointer, just hand the the entire object to bind, and let it resolve when you use the bind, or in this case when you add it to the std::function.

Func f;
std::function<void(int)> func = std::bind(f, std::placeholders::_1);

or even better, just assign f to the std::function

Func f;
std::function<void(int)> func = f;
Dave S
  • 18,677
  • 3
  • 43
  • 65