Reputation: 769
I have gradually accumulated some open questions about the language's initialization syntax. Searching for answers can sometimes be relatively difficult when one does not know what to search for or is not aware of the correct terminology.
Are my assumptions as expressed in the comments below correct, and what is actually happening if not? I am using C++11.
struct Foo{};
Foo; //1: Error, this fails for all types, built-in or otherwise
Foo(); //2: rvalue created by an explicit call to the default ctor "Foo::foo()"
Foo{}; //3: rvalue created by specifying an empty initializer list,
// ..at which point is the default constructor called? How
// ..does this actually differ from #2?
Foo={}; //4: Error, why does this syntax not work?
Foo(){}; //5: Error, this one is quite obvious considering #2
Foo()={}; //6: what exactly happens here?
Foo f; //7: instance created by implicit call to default constructor
Foo f{}; //8: instance created by initializer list, similar to #3
Foo f={}; //9: similar to #8
Foo f(); //10: function declaration.
Foo f()={};//11: Error, this is a malformed function declaration
Foo f(){} //12: function definition
Upvotes: 0
Views: 154
Reputation: 119089
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.
Upvotes: 1
Reputation: 769
After putting some thought into it, I arrived at the following conclusion:
Foo f;
is a default initialization.Foo();
, Foo{};
and Foo f{};
are value initializations.Foo f={};
is an aggregate initialization.Foo()={};
and Foo{}={};
are actually multiple operations: If I'm correct, a value initialization of Foo()
, followed by a second value initialization of {}
(the type is deduced by the compiler), and finally ending with an assignment operation (by the default assignment operator).Foo f();
is treated as a function declarationFoo f(){}
is a function definitionUpvotes: 0