Scott Meyers invented the term "universal reference" during C++11's development, but the committee decided that the term "forwarding reference" was a more descriptive choice and made it the official name. Anyway, deduced
class template arguments are not forwarding references. Therefore in your first snippets,
Func&& is always an rvalue reference type, it ought to be moved from.
It is possible to initialize an rvalue reference from an lvalue expression with function type. Expressions that name functions, like
f, are always lvalue expressions, but this is a special case probably added to ease generic programming:
http://eel.is/c++draft/dcl.init.ref#5.3
Both definitions work but which is the best |
The former is certainly better, but both are non-ideal.
If Logger2 contains an rvalue reference to
Func, then declarations like
Logger2 logger([]{ std::cout << "func"; }, "whatever");
Immediately create a dangling reference.
It's better to work with lvalue references, so that the above would result in a compile-time error, although I second helios and suggest storing
func by value:
mbozzi wrote: |
---|
Storing a reference is contrary to existing practice, has negative performance implications, and makes the interface more challenging to use properly. If value semantics were supported, the user could always pass std::ref(func) if reference semantics were desired. |
http://cplusplus.com/forum/beginner/269786/
Reference members also make code harder to implement. Sticking with values should result in fairly straightforward code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
#include <iostream>
#include <utility>
template<typename Fn> class logger
{
Fn f_;
public:
explicit logger(Fn f): f_(std::move(f)) {}
auto operator()() const { return f_(); }
};
int main()
{
logger l([]{ std::cout << "hello!\n"; });
l();
}
|