int foo = foo;
compiles.
Which part of the C++ standard allows this?
int& foo(); is a function returning a reference to int . Your provided function returns int without reference. You may do int& foo() { static int i = 42; return i; } int main() { int& foo(); foo() = 42; } Follow this answer to receive notifications.
Foo (pronounced FOO) is a term used by programmers as a placeholder for a value that can change, depending on conditions or on information passed to the program.
In C++ int& foo() declares a function having a function named foo() of data type int&. The foo() function of type int& returns a reference to an int instead of a int value. Likewise, we can declare the foo() with other data types as well.
3.3.1 Point of declaration [basic.scope.pdecl]
The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any),
The behaviour is well defined if the declaration is at file scope. If you have the declaration at function scope and if you use foo
later on [which would be initialized to some unspecified value in that case] the behaviour would be undefined.
This?
int main() {
int foo = foo;
}
The object foo
does exist after the =
, according to [basic.scope.pdecl]
:
The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any).
However, the program as a whole is undefined, because you use (on the RHS) an uninitialised value:
int x = x;
Here [..]x
is initialized with its own (indeterminate) value.
And:
Though "inferred and ill-specified" by the standard, an lvalue-to-rvalue conversion is performed on the RHS expression foo
.
And ([conv.lval]
):
An lvalue (3.10) of a non-function, non-array type T can be converted to an rvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the lvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior.
With proper warning levels, you will get told about it; however, programs invoking Undefined Behaviour are allowed to compile. They just can do anything at all when you run them.
Or, what about this?
int foo = foo;
int main() {}
Notice that foo
is a "global". These are zero-initialised as a first step, according to [basic.start.init]
:
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.
So you'll get an int foo
with value 0; it's valid, at this point, as per [basic.scope.pdecl]
above, and as per [stmt.decl]
:
The zero-initialization (8.5) of all local objects with static storage duration (3.7.1) is performed before any other initialization takes place. [..]
You then value-initialise it to foo
(itself), i.e. 0.
This is well-defined... if a little cryptic.
In the interests of thoroughness, here's a third and final case:
int foo = 42;
int main() {
int foo = foo;
}
Sadly, this is the same as the first case. Since the local foo
is already declared and in scope by the time the initializer is evaluated, the initializer uses the local foo
and you're still stuck with the Undefined Behaviour. The global foo
is not used.
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