29

The following code works fine

#include <functional>

using namespace std;
using namespace std::placeholders;

class A
{
  int operator()( int i, int j ) { return i - j; }
};

A a;
auto aBind = bind( &A::operator(), ref(a), _2, _1 );

This does not

#include <functional>

using namespace std;
using namespace std::placeholders;

class A
{
  int operator()( int i, int j ) { return i - j; }
  int operator()( int i ) { return -i; }
};

A a;
auto aBind = bind( &A::operator(), ref(a), _2, _1 );

I have tried playing around with the syntax to try and explicitly resolve which function I want in the code that does not work without luck so far. How do I write the bind line in order to choose the call that takes the two integer arguments?

James McNellis
  • 348,265
  • 75
  • 913
  • 977
bpw1621
  • 2,962
  • 2
  • 32
  • 35
  • 5
    `A::operator()` does not refer to a single function but to a family of functions : I think you have to cast to it in order to 'select' the right overload. I'm not validating this as an answer as I'm unfamiliar with C++0x and I may not be aware of a more elegant solution. – icecrime Nov 11 '10 at 21:40
  • I wrote [an answer to a similar question](/a/37302949), showing three ways to coerce the argument to the correct type. – Toby Speight Jun 21 '18 at 12:32

3 Answers3

48

You need a cast to disambiguate the overloaded function:

(int(A::*)(int,int))&A::operator()
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 1
    I'd write that as `static_cast(&A::operator())`, to be explicit that it isn't a conversion – Caleth Jun 21 '18 at 10:49
  • You should be able to simply assign to a temporary of the right type (`int(A::*method)(int,int) = &A::operator();`) and use that. Personally, I have a small `up_cast()` method: `template T up_cast(U value) { return value; }` - that's even clearer than `static_cast` that there's no conversion going on. – Toby Speight Jun 21 '18 at 12:23
18

If you have C++11 available you should prefer lambdas over std::bind since it usually results in code that is more readable:

auto aBind = [&a](int i, int j){ return a(i, j); };

compared to

auto aBind = std::bind(static_cast<int(A::*)(int,int)>(&A::operator()), std::ref(a), std::placeholders::_2, std::placeholders::_1);
Patryk
  • 22,602
  • 44
  • 128
  • 244
sigy
  • 2,408
  • 1
  • 24
  • 55
  • 1
    Not only more readable, but also better performing. I remember watching a presentation about it. The conclusion was that std::bind disallows compiler from performing various optimizations, while it has no problems, when using lambdas. – etam1024 Jun 18 '18 at 19:39
0

There are some "lift" macros available that automate passing overload sets as parameters by wrapping them into a lambda that simply forwards all parameters passed to it. One that is provided by Boost can make the code compile via

#include <boost/hof/lift.hpp>

auto aBind = bind(BOOST_HOF_LIFT(&A::operator()), ref(a), _2, _1 );

There are also proposals for making it easier to pass overload sets, see e.g. P0834, but I don't know whether this will find or found consensus.

lubgr
  • 37,368
  • 3
  • 66
  • 117