I say: Pass (template) function objects per Forwarding references! and not per value. The reason is simple: it works also with function objects with state.
https://en.cppreference.com/w/cpp/language/reference
A little example will show it:
#include <iostream> #include <random> using namespace std; template<typename Function> auto perValue(Function f) { return f(); } template<typename Function> auto perForwardReference(Function&& f) { return f(); } int main() { std::minstd_rand gen(1156823295); cout << "Generate 5 random numbers:\n"; cout << "calls to perValue:\n"; for(int i=0; i < 5; i++) { cout << perValue(gen) << "\n"; } cout << "calls to perForwardReference:\n"; for(int i=0; i < 5; i++) { cout << perForwardReference(gen) << "\n"; } }
Generate 5 random numbers:
calls to perValue:
4
4
4
4
4
calls to perForwardReference:
4
193084
730423176
870612250
1216431607
It doesn’t work because the random number generate object has a state. The call to function perValue() change this state on a copy of the generator. And not the one, we pass as argument. But there is no compile time error. Not a single warning. That's the worst case IMO.
The C++ standard and Scott Meyers book "Effective STL" recommend to pass by value. IMO for historical reasons.
C++11 §25.1/10:
[ Note: Unless otherwise specified, algorithms that take function objects as arguments are permitted to copy those function objects freely. Programmers for whom object identity is important should consider using a wrapper class that points to a noncopied implementation object such as reference_wrapper(20.8.3), or some equivalent solution. —end note ]
stackoverflow: why function objects should be pass-by-value
The standard should be updated and the book is horrible outdated. It was written 2008 and forward references come with C++2011. The old solution is to wrap the function into something which can be pass by value, but also change the state. We have now (2011) std::function for that task. And not this ugly thing in the book.