Possible Duplicate:
template pass by value or const reference or…?
What is the good practice in the following for a function taking a function as a parameter :
template<class Function> void test1(Function f);
template<class Function> void test2(Function& f);
template<class Function> void test3(const Function& f);
where the passed function can be a functor, a std::function, a function pointer or a lambda function.
Use universal references and you won't need to think about it:
template<class Function> void test(Function&& f);
When an argument is passed to a function template deducing the argument's type, it is an interesting question as to how the argument should be passed. It is worth noting that the exact nature of the use of the argument doesn't matter: Whether the argument is used as a function object, an iterator, a value, etc. is fairly irrelevant to answer. There are four options:
template <typename T> void f(T&& a)template <typename T> void f(T& a)template <typename T> void f(T const& a)template <typename T> void f(T a)It matters a bit as to what the function template actually does: If all f() does with its argument a is to forward it to another function, you want to pass by universal reference. The called function will sort out the details an reject inappropriate options. Of course, although generally useful, forwarding functions are somewhat boring.
If f() actually does something with the object, we can normally immediately discard two of the options:
T const& isn't doing us much good either: we got a reference to an object whose life-time we can't control and which we can neither move from nor get it copy/move-elided.Passing an object by non-const reference can be useful if the object itself gets modified. This is clearly an important part of the contract of the function and an imposed design choice which can't be overridden by a client of the function when taken.
The preferred approach is to take arguments by value. Generally, this makes the definition of the function's behavior much easier and actually keeps the choice whether the type should follow value or reference semantics open for the user! Just because something is passed by value doesn't mean that the objects of interest are also passed by value. Specifically for the case of function object, the standard C++ library even provides a generic adapter giving a value type reference semantics: std::ref().
Of course, interface design is subtle and there will be cases where each one of the options is warranted. However, as a general rule of thumb, I think it is very simple:
... and, of course, these rules only apply to arguments to function templates whose type is deduced.
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