Passing functions in C++

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.


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.

Tags:

C++

C++17