Suppose I want to write a function that calls a nullary function 100 times. Which of these implementations is best and why?
template<typename F> void call100(F f) { for (int i = 0; i < 100; i++) f(); } template<typename F> void call100(F& f) { for (int i = 0; i < 100; i++) f(); } template<typename F> void call100(const F& f) { for (int i = 0; i < 100; i++) f(); } template<typename F> void call100(F&& f) { for (int i = 0; i < 100; i++) f(); }
Or is there a better implementation?
Update regarding 4
struct S { S() {} S(const S&) = delete; void operator()() const {} }; template<typename F> void call100(F&& f) { for (int i = 0; i < 100; i++) f(); } int main() { const S s; call100(s); }
Function Call When calling a function with a function parameter, the value passed must be a pointer to a function. Use the function's name (without parentheses) for this: func(print); would call func , passing the print function to it.
We cannot pass the function as an argument to another function. But we can pass the reference of a function as a parameter by using a function pointer. This process is known as call by reference as the function parameter is passed as a pointer that holds the address of arguments.
Passing Functions as Arguments. Functions are data, and therefore can be passed around just like other values. This means a function can be passed to another function as an argument. This allows the function being called to use the function argument to carry out its action.
Arguments in C and C++ language are copied to the program stack at run time, where they are read by the function. These arguments can either be values in their own right, or they can be pointers to areas of memory that contain the data being passed. Passing a pointer is also known as passing a value by reference.
Passing pointers to functions in C. C programming allows passing a pointer to a function. To do so, simply declare the function parameter as a pointer type.
Parameter Passing Techniques in C/C++. There are different ways in which parameter data can be passed into and out of methods and functions. Let us assume that a function B() is called from another function A(). In this case A is called the “caller function” and B is called the “called function or callee function”.
Passing a function as an argument is a useful concept in C/C++. This concept has already been used while passing a custom comparator function as an argument in std::sort() to sort a sequence of objects as per the need. In this article, we will discuss different ways to design functions that accept another function as an argument.
The following function ( print) is an example of a function which could be passed to func as a parameter because it is the proper type: When calling a function with a function parameter, the value passed must be a pointer to a function. Use the function's name (without parentheses) for this: would call func, passing the print function to it.
I would use the first one (pass the callable by value).
If a caller is concerned about the cost of copying the callable, then they can use std::ref(f)
or std::cref(f)
to pass it using reference_wrapper
.
By doing this, you provide the most flexibility to the caller.
The only runtime cost of
template<typename F> void call100(F&& f) { for (int i = 0; i < 100; ++i) f(); }
is that it can have more versions (copies of code) if you pass f
in multiple ways. With MSVC or the gold linker with ICF, those copies only cost compile time unless they differ, and if they differ you probably want to keep them.
template<typename F> void call100(F f) { for (int i = 0; i < 100; ++i) f(); }
this one has the advantage of being value semantics; and following the rule of taking values unless you have good reason not to is reasonable. std::ref
/std::cref
let you call it with a persistant reference, and for prvalues c++17 guaranteed elision will prevent a spurious copy.
As a joke you could do:
template<typename F> void call100(F&& f) { for (int i = 0; i < 99; ++i) f(); std::forward<F>(f)(); }
but that relies on people having &&
overloads on their operator()
, which nobody does.
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