Does the standard define what happens with this code?
#include <iostream>
template <typename Func>
void callfunc(Func f)
{
::std::cout << "In callfunc.\n";
f();
}
template <typename Func>
void callfuncref(Func &f)
{
::std::cout << "In callfuncref.\n";
f();
}
int main()
{
int n = 10;
// n is captured by value, and the lambda expression is mutable so
// modifications to n are allowed inside the lambda block.
auto foo = [n]() mutable -> void {
::std::cout << "Before increment n == " << n << '\n';
++n;
::std::cout << "After increment n == " << n << '\n';
};
callfunc(foo);
callfunc(foo);
callfuncref(foo);
callfunc(foo);
return 0;
}
The output of this with g++ is:
$ ./a.out
In callfunc.
Before increment n == 10
After increment n == 11
In callfunc.
Before increment n == 10
After increment n == 11
In callfuncref.
Before increment n == 10
After increment n == 11
In callfunc.
Before increment n == 11
After increment n == 12
Are all features of this output required by the standard?
In particular it appears that if a copy of the lambda object is made, all of the captured values are also copied. But if the lambda object is passed by reference none of the captured values are copied. And no copies are made of a captured value just before the function is called, so mutations to the captured value are otherwise preserved between calls.
The type of the lambda is simply a class (n3290 §5.1.2/3), with an
operator()which executes the body (/5), and an implicit copy constructor (/19), and capturing a variable by copy is equivalent to copy-initialize (/21) it to a non-static data member (/14) of this class, and each use of that variable is replaced by the corresponding data member (/17). After this transformation, the lambda expression becomes only an instance of this class, and the general rules of C++ follows.That means, your code shall work in the same way as:
And it is obvious what
callfuncrefdoes here.