Initialization is a confusing topic because the various forms of initialization (direct-initialization, list-initialization, value-initialization, etc.) are not all mutually exclusive.
I went through the C++11 standard and read all the gory details, if you're curious. Here's a line-by-line analysis.
struct Foo{};
Since Foo
is a class type, default-initialization of Foo
calls the default constructor (8.5 [dcl.init] paragraph 6).
Since Foo
is a non-union class type without a user-provided constructor, value-initialization of Foo
entails zero-initialization followed by calling the implicitly-declared default constructor, if it is non-trivial. (8.5 [dcl.init] paragraph 7).
In this case, the implicitly-declared default constructor is trivial (12.1 [class.ctor], paragraph 5) and is equivalent to Foo::Foo() {}
(Id., paragraph 6).
Foo
is an aggregate and may be initialized by an initializer list. (8.5.1 [dcl.init.aggr], paragraph 1)
Foo;
Ill-formed. However, the declaration Foo Foo;
is valid and declares a variable named Foo
of type Foo
. The expression Foo;
would then become valid. Needless to say, you shouldn't do this.
Foo();
This is an explicit type conversion. Since Foo
is a non-array complete object type, this expression creates a prvalue of type Foo
, which is value-initialized. (5.2.3 [expr.type.conv] paragraph 2).
Foo{};
This is also an explicit type conversion, which creates a prvalue of type Foo
which is direct-list-initialized (Id., paragraph 3). Since the braced-init-list is empty and Foo
is a class type with a default constructor, the object is value-initialized (8.5.4 [dcl.init.list], paragraph 3).
Foo={};
Well, this doesn't make any sense. What did you expect it to do? (Note: Again, this becomes well-defined if Foo
is a variable.)
Foo(){};
I agree, it's pretty obvious that this is ill-formed, at least as an expression. It is, however, valid syntax for the definition of the default constructor of Foo
. (The extraneous semicolon is an empty declaration.)
Foo()={};
This creates the prvalue Foo()
as previously detailed, then performs an assignment to it. This is allowed even though Foo()
is an rvalue (13.5 [over.oper], paragraph 7). This expression on the whole is equivalent to Foo().operator=({})
(5.17 [expr.ass], paragraph 9). It constructs a temporary Foo
by aggregate-initialization from the braced-init-list {}
, binds the temporary Foo
to an rvalue reference, Foo&&
, and calls Foo
's implicitly defined move assignment operator (12.8 [class.copy], paragraphs 20-21).
Foo f;
This invokes default initialization (8.5 [dcl.init], paragraph 11).
Foo f{};
This is list-initialization, since the initializer is a braced-init-list (8.5 [dcl.init], paragraph 16). Specifically it is direct-list-initialization (8.5.4 [dcl.init.list], paragraph 1). As in the case of Foo{}
, value-initialization is performed.
Foo f={};
This is copy-initialization (8.5 [dcl.init], paragraph 14). Again, since the initializer is a braced-init-list, it is list-initialization; specifically, copy-list-initialization (8.5.4 [dcl.init.list], paragraph 1). Again, value-initialization is performed.
Foo f();
This is indeed a function declaration, since a statement which could be interpreted as either a function declaration or an object declaration is always interpreted as the former (8.2 [dcl.ambig.res], paragraph 1).
Foo f()={};
This can be interpreted as neither a valid object declaration nor a valid function declaration, so it is ill-formed.
Foo f(){}
Indeed, this is a function definition.