Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opposite of std::bind, pass in different functions for given parameters

Tags:

c++

std

stdbind

I have several functions with almost identical signatures (made much shorter than actual code):

int hello(A a, B b, C c, int n);
int there(A a, B b, C c, int n);
int how(A a, B b, C c, int n);
int are(A a, B b, C c, int n);
...

And so on. Then during invocation, the code creates the parameters once and then passes the same objects to every function, except n:

A a; B b; C c;
hello(a, b, c, 240);
there(a, b, c, 33);
how(a, b, c, 54);
are(a, b, c, 67);

What I would like to achieve is something similar to how std::bind is normally used, except I would like to swap out the function. e.g:

auto uber_func = std::something_stack_overflow_recommends(..., a, b, c)
uber_func(hello, 240);
uber_func(there, 33);
uber_func(how, 54);
uber_func(are, 67);

It wasn't clear to me from the documentation of std::bind whether it could do this. Do you have any suggestions?

like image 899
jeanluc Avatar asked May 12 '20 22:05

jeanluc


Video Answer


2 Answers

You can use a Lambda, which made std::bind mostly obsolete, as it is easier to use:

  auto uber_func = [&](std::function<int(A, B, C, int)> f, int n) {
    return f(a, b, c, n);
  };

  uber_func(hello, 240);
  uber_func(there, 33);
  uber_func(how, 54);
  uber_func(are, 67);

The first solution enforces that all functions have the same well-known interface. If needed it could be generalized to support also different types of functions:

  auto uber_func = [&](auto f, int n) {
    return f(a, b, c, n);
  };

The second solution is more general and avoids the performance overhead of the first solution. Small drawback: it will require a C++14 compiler, while the first should work on any C++11 compiler. If that is no problem, I would prefer the second solution over the first one.

I realized that you asked about how to do it with std::bind and I did not answer that. However, since C++11 Lambdas largely replaced std::bind. Since C++14, it is even clearer, as further improvements have been added. Unless compatibility with C++98 is a strict requirement, I would recommend to avoid std::bind in favor of Lambdas.

like image 100
Philipp Claßen Avatar answered Nov 15 '22 22:11

Philipp Claßen


You can construct an object with all the parameters but the last:

template<typename A, typename B, typename C>
struct uber
{
   A a;
   B b;
   C c;

   uber(A a, B b, C c) : a(a), b(b), c(c) {}

   template<typename F> 
   auto operator()(F f, int n) { f(a,b,c,n); }
};

and then use the templated call operator to call the individual functions:

A a; B b; C c;
auto uber_func = uber{a,b,c};
uber_func(hello, 240);
uber_func(there, 33);
uber_func(how, 54);
uber_func(are, 67);
like image 44
cigien Avatar answered Nov 15 '22 20:11

cigien