Calling a function (or function object) dynamically, through a pointer known at runtime, is a common programming scenario. Almost all languages support this use case.
Lisp, for example, has apply and funcall.
When using apply, you can see that the arguments are passed via a separate list object. With funcall, however, the arguments are passed directly in line.
Likewise, Mathematica has Apply and Construct:
As you can see, the idea is quite similar to Lisp.
Even in C++ (prior to C++17), it has always been possible to call functions and methods dynamically through respective pointers. Take a look at the following example.
What is nice about C++17 is that it provides two methods apply and invoke (defined in the std namespace) that make dynamic method invocation more flexible and uniform. You will see that the behavior is quite similar to Lisp and Mathematica.
To make use of std::apply and std:: invoke you have to #include <functional>
Let us define a simple function that takes 3 integers and returns their sum. Let us also define a class (actually a struct) that has a public member function and an instance variable.
The apply method takes two arguments namely, the callable object that needs to be dynamically invoked, and the data structure that contains the arguments for the callable object. The data structure could be std::pair, std::tuple or std::array.
So let us create a tuple and array of 3 integers and see how to use apply
Notice that we cannot pass the original arguments directly in line when calling apply.
This is the difference between apply and invoke. invoke requires the arguments to be passed in line as if we are calling the function directly.
apply comes in quite handy if we are calling a varargs function such as printf. We can conveniently bundle all the arguments in a tuple and pass it to apply.
Let us consider the case where instead of calling normal functions, we wish to invoke member functions. Remember that in order to invoke a member function, we need an object recipient (unless the function is static).
Both apply and invoke make this process quite simple and uniform.
Compare this with the traditional call syntax (shown within comments above). Hope you are able to appreciate the benefits of apply and invoke.
Implementations of these two functions depend on some fancy template coding tricks, but fortunately as users, we do not need to know the details.
You can download my example source code here.
Have a great weekend!
Recent Comments