While reading this part of C++14 (a free draft N4141, closest to C++14):
9.8 Local class declarations [class.local]
[..] The name of a local class is local to its enclosing scope. [..]
Declarations in a local class shall not odr-use (3.2) a variable with automatic storage duration from an enclosing scope. [ Example:
//[..] void f() { static int s ; int x; // [..] struct local { int g() { return x; } // error: odr-use of automatic variable x int h() { return s; } // OK // [..] }; } local* p = 0; // error: local not in scope
—end example ]
I noticed, that, first - I can define p
with return value auto deduction:
auto f()
{
static int s;
int x;
struct local
{
int h() { return s; }
};
return local{};
}
decltype(f())* p = 0; // OK - ignored, that local is not in scope!
Maybe it seems ok, why not to use local type by deducing it from function return value, but - it seems in this way I can access local s
variable before it is constructed:
struct TalkativeInt
{
TalkativeInt() : value()
{
std::cout << "TalkativeInt()\n";
}
TalkativeInt(int value) : value(value)
{
std::cout << "TalkativeInt(" << value << ")\n";
}
int value;
};
auto f()
{
static TalkativeInt s = 7;
int x;
struct local
{
auto h() { return s.value; }
};
return local{};
}
decltype(f())* p = 0;
int main() {
decltype(f()) l;
std::cout << l.h();
}
Output is just::
0
But one might expect:
TalkativeInt(7)
7
Both clang and gcc do not protest in any way, see demo.
I wonder, maybe such case should be mentioned somehow either in
9.8 Local class declarations [class.local]
or in
7.1.6.4 auto specifier [dcl.spec.auto]
?
Of course, I feel that reading (and writing) from variable before it is constructed is bad thing, but I have not found anything about that in standard - probably, it was not possible before C++14? Or there are some basic rules I just overlooked?
The rule for static local variables is plain and simple:
Dynamic initialization of a block-scope variable with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization.
And accessing an object's members before its construction is disallowed by [basic.life]/(7.1).