My question is about lambda scope for the static member initializers. Consider the following test:
#include <functional>
#include <iostream>
struct S {
static const std::function<void(void)> s_func;
};
const std::function<void(void)> S::s_func = []() {
std::cout << "Hello from " << __PRETTY_FUNCTION__ << std::endl;
};
int main(void) {
S::s_func();
return 0;
}
gcc starting from 4.8 defines the lambda in the scope of S, so the program outputs something like this:
Hello from S::<lambda()>
(gcc-4.8.2 has a different definition for __FUNCTION__
& Co macros, but nevertheless the lambda is still defined within S
)
Meanwhile gcc-4.7 defines the lambda in the global scope, so the program outputs
Hello from <lambda()>
Probably newer gcc are more standard-compliant. However I'd like to ask if the standard actually specifies this aspect or it can be implementation-dependent.
Update: as @user5434961 suggested that all __FUNCTION__
-alike macros are implementation dependent, so it's better to avoid them in a standard-compliant test. So here is the example which can be compiled if a compiler defines such lambdas within S
scope and breaks the compilation otherwise:
#include <functional>
#include <iostream>
struct S {
static const std::function<void(void)> s_func;
private:
static const int s_field;
};
const std::function<void(void)> S::s_func = []() {
std::cout << "Hello from S::s_func. S::s_field = " << S::s_field << std::endl;
};
const int S::s_field = 1;
int main(void) {
S::s_func();
return 0;
}
This issue has been raised before but I cannot find the relevant bug report. Here's a broken link for a MSVC bug report that was supposedly filed (it's still not fixed in 2015: you can test it at rise4fun). It has however been fixed somewhere between 4.7 and 4.8 for GCC. The relevant standardese used to back this up as a bug is:
[C++11, 9.4.2/2] The initializer expression in the definition of a
static
data member is in the scope of its class.[C++11, 5.1.2/2] The evaluation of a lambda-expression results in a prvalue temporary (12.2). This temporary is called the closure object. A lambda-expression shall not appear in an unevaluated operand (Clause 5).
[C++11, 5.1.2/3] The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression.
Previously
Why lambda in static initializer can't access private members of class in VC++2013?
C++11 lambdas can access my private members. Why?
Why is it not possible to use private method in a lambda?
I guess it should be in the class scope. Quoted from cppreference (emphasis mine):
The lambda expression constructs an unnamed prvalue temporary object of unique unnamed non-union non-aggregate type, known as closure type, which is declared (for the purposes of ADL) in the smallest block scope, class scope, or namespace scope that contains the lambda expression.
In the out-of-line definition of S::s_func
, you enter into the scope of S
the time S::
is encountered. So, the lambda expression is contained in the class scope of S
. As the closer type is a member of S
, access to private members of S
is granted.
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