4

The following code works, but I feel that the line worker([this](int a, long b, int* c){receiver(a, b, c);}); is sort of redundant because it is repeating the signature of receiver. Instead of passing a lambda function that in turn calls the member function, can I somehow pass the member function directly?

using callback = std::function<void(int, long, int*)>;

void worker(callback c)
{
    c(1,2L,(int*)3);
}

class Caller
{
public:
    Caller()
    {
        worker([this](int a, long b, int* c){receiver(a, b, c);});
    }

    void receiver(int a, long b, int* c)
    {
    }
};
Damn Vegetables
  • 11,484
  • 13
  • 80
  • 135

3 Answers3

4

If you have access to C++20, use bolov's answer. If not…

Though this still uses a lambda, you can take advantage of an argument pack to avoid duplicating the signature:

worker([this](auto... params) { receiver(params...); });

This requires C++14 or newer.

Perfect forwarding can be added if you have more complex types and want to avoid copies:

worker([this](auto&&... params) {
    receiver(std::forward<decltype(params)>(params)...);
});
spectras
  • 13,105
  • 2
  • 31
  • 53
3

std::bind is the classical approach, that avoids the need to explicitly spell out the forwarding signature:

using namespace std::placeholders;

// ...

    worker(std::bind(&Caller::receiver, this, _1, _2, _3));

C++20 also has std::bind_front; it reduces this verbiage, somewhat.

You cannot pass a pointer to a member function "directly". This is because a member function requires a specific instance of an object whose member function should get invoked. So, in some form of fashion, in some way, you cannot avoid this, or some other instance of the object, to be involved in the process. This is fundamental to C++. The only thing that can be done here is to find some syntactic sugar, which is basically all this is, here.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • though `std::bind` is considered outdated and clang-tidy will mark this code with a warning. Also, placeholders: 1) hide arguments' types from the reader 2) hide arguments' types from the compiler thus introducing the need for "manual" resolution which will look waaaay uglier than forwarding – Sergey Kolesnik Dec 05 '21 at 01:18
3

The cleanest way is C++20's std::bind_front:

worker(std::bind_front(&Caller::receiver, this));

Why use `std::bind_front` over lambdas in C++20?

bolov
  • 72,283
  • 15
  • 145
  • 224
  • This seems to be the cleanest solution, and it worked in VC++ 2022, but unfortunately the compiler I am using (ESP8266 SDK) seems to be supporting only C++17, and it does not seem to have `bind_front` but only `bind`. So close... – Damn Vegetables Dec 04 '21 at 21:41
  • @DamnVegetables yes, C++20 is pretty new. Keep this solution in mind for the future :p – bolov Dec 04 '21 at 22:18