I would like to have a reference to the call of an object's method. Is this possible in C++? What is the technical name I should be searching for? Can we supply some arguments with predetermined values?
The following code highlights what I would like to use
struct Foo {
  void barNoArgs();
  void barMultArgs(int, float, bool);
};
Foo f;
auto& refToBarNoArgs = f.barNoArgs;
refToBarNoArgs(); // should call f.barNoArgs()
auto& refToBarMultArgs = f.barMultArgs(?, 3.14f, ?);
refToBarNoArgs(42, true); // should call f.barMultArgs(42, 3.14f, true)
What is the technical name I should be searching for?
This is called Argument Binding, or sometimes a Partial Function
But first, you should know that both of your examples are the exact same problem. Methods are essentially functions with a hidden first parameter called this after all.
So refToBarNoArgs is a function taking 0 arguments that calls Foo::barNoArgs with the first argument pre-populated. And refToBarNoArgs is a function that takes 2 arguments, and calls Foo::barMultArgs with the first and third arguments pre-populated, and the second and fourth with its own arguments.
The key point here is that your "reference" can't be a reference in the C++ sense of the term. References don't actually exist (as in there is no object associated with the reference itself). Here, in both cases, we need to store the values of the pre-populated arguments, as well as manage their lifetimes. It has to be an actual object, with storage and lifetime, that behaves like a function. This is called a Functor.
The language provides us with a convenient bit of syntactic sugar to facilitate creating both the type and a single instance of such a functor all at once: Lambdas.
auto refToBarNoArgs = [&f](){f.barNoArgs();};
refToBarNoArgs();
auto refToBarMultArgs = [&f](int i, bool b){f.barMultArgs(i, 3.14f, b);};
refToBarNoArgs(42, true);
If you are not familiar with lambdas, be wary of the [&f] in my examples. It means that the lambda captures f by reference. Because of this, they should not be allowed to live (for example, stored in an std::function<>) longer than the lifetime of f.
You can also use std::bind to get effectively the same thing. In fact, the end result is very close to your original code:
#include <functional>
struct Foo {
  void barNoArgs();
  void barMultArgs(int, float, bool);
};
int main() {
    using namespace std::placeholders;  // for _1, _2, _3...
    Foo f;
    auto refToBarNoArgs = std::bind(&Foo::barNoArgs, &f);
    refToBarNoArgs();
    auto refToBarMultArgs = std::bind(&Foo::barMultArgs, &f, _1, 3.14f, _2);
    refToBarNoArgs(42, true);
}
Personally, I find lambdas much clearer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With