typedef std::function<void(std::string)> const& fn;
This isn't a std::function
, it is a reference to a std::function
.
TestClass(fn _f) : f(_f) { F(); }
fn f;
Here you take a const&
to a std::function
and bind it to another const&
to a std::function
. The F()
in the body of the constructor works, as the reference is valid at least as long as the constructor is.
TestClass t([](std::string str) {std::cout << str << std::endl; });
This creates a std::function
temporary created from the lambda. This temporary lasts as long as the current line (until the ;
).
Then the temporary std::function
is discarded.
As TestClass
takes the std::function
by const&
, it doesn't extend the temporaries lifetime.
So after the line, any call of the std::function const&
is undefined behavior, which you see in the call to .F()
later.
fn __f = [](std::string str) {std::cout << str << std::endl; };
This does reference lifetime extending. The temporary std::function
created from the lambda has its lifetime extended to the lifetime of the __f
variable.
As an aside, this line also makes your program ill formed, no diagnostic required, by having a variable containing a double underscore. Such identifiers are reserved for the implementation of the compiler, you may not create them.
TestClass t(__f);
We then pass this reference (referring to a lifetime extended temporary), and everything works.
auto __f = [](std::string str) {std::cout << str << std::endl; };
This creates a variable __f
(see above, bad name) that is a lambda.
A lambda is not a std::function
. A std::function
can be created from a lambda implicitly.
TestClass t(__f);
This creates a temporary std::function
from the lambda, passes it to the TestClass
constructor, then destroys the temporary.
After this line, the call to .F()
ends up following a dangling reference, and undefined behavior results.
Your core problem may be that you think a lambda is a std::function
. It is not. A std::function
can store a lambda.
Your second problem is typedefing something as a const&
, which is almost always a really stupid idea. References behave differently than values in fundamental ways.
Your third problem is the double understore in your variable names. (Or an identifier starting with an _
followed by a capital letter).
If you want to know how std::function
works and what it is, there are plenty of good SO posts on the subject with various levels of technical detail.