Let we have procedure formed as class. Only constructor call makes some side effect. No need to handle class instance in memory after call. Following code instantiate that class:
struct A{
A(int){}
};
int main() {
A(0);//right. Pass const to ctor
int x=0;
A(x);//bad. Compiler interpret like A x;
(A(x));//right. New temporary object passed to brackets
A((int)x);//right. Pass temporary int to ctor
return 0;
}
(see also on Online IDE)
Why A(x); interpret as variable x declaration instead of temporary A object instantiaton?
From the C++11 standard, ISO/EIC 14882 §6.8 [stmt.ambig] ¶1 (emphasis mine):
There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable
from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.
To apply this to your question, A(x); can parse as either "call the function A / construct a temporary object of type A, and pass x as the only function/constructor argument" or "declare a variable x of type A." The standard says that in this case, it should be parsed as a variable declaration.
Your other examples are not ambiguous because they cannot be parsed as a variable declaration, and so they are parsed as a call to A's constructor.
That's because what you consider should be the parameter list to the ctor, (x) is being interpreted as "x in parentheses". Thus, A(x) is read as A (x) is read as A x.
In the other cases, the compiler has a hint suggesting that it should generate an A instance, calling the ctor with the arguments supplied.
Related
I read that this code A a( A() ); was interpreted by the compiler as a function declaration while here I clearly see that A() is a function that returns an object. How can it be something else that the construction of a A object ?
I've just read entirely the Function declaration page of cppreference : https://en.cppreference.com/w/cpp/language/function and I don't see anywhere that the parameters list can look like that A().
I don't understand how The most vexing parse can be valid C++.
A() isn't a function declaration by itself, but it can be the type of a function.
For instance, suppose I declare the following function: A makeAnA();. The type of makeAnA is A(): A function that takes no arguments and returns an A.
Quoting cppreference on functions:
Each function has a type, which consists of the function's return type, the types of all parameters (after array-to-pointer and function-to-pointer transformations, see parameter list) , whether the function is noexcept or not (since C++17), and, for non-static member functions, cv-qualification and ref-qualification (since C++11). Function types also have language linkage.
So a function that has zero parameters, returns an A, and isn't noexcept has the type A().
Therefore, it's possible to interpret A a( A() ); as a function declaration. It declares that a accepts a single, unnamed argument of type A(), and returns an A as its result. Because it's possible to interpret this as a function declaration, it is required by the standard that it is so interpreted.
struct B {
B() throw();
B(const B&) = default; // implicit exception specification is noexcept(true)
B(B&&, int = (throw Y(), 0)) noexcept;
~B() noexcept(false);
};
int n = 7;
struct D : public A, public B {
int * p = new int[n];
// D::D() potentially-throwing, as the new operator may throw bad_alloc or bad_array_new_length
// D::D(const D&) non-throwing
// D::D(D&&) potentially-throwing, as the default argument for B's constructor may throw
// D:: D() potentially-throwing
};
Consider the above code which is cited from except.spec#11. I have no doubt to the exception specification of all constructors of D except for D::D(D&&), which obeys the following rule:
An implicitly-declared constructor for a class X, or a constructor without a noexcept-specifier that is defaulted on its first declaration, has a potentially-throwing exception specification if and only if any of the following constructs is potentially-throwing:
a constructor selected by overload resolution in the implicit definition of the constructor for class X to initialize a potentially constructed subobject, or
a subexpression of such an initialization, such as a default argument expression, or,
for a default constructor, a default member initializer.
Obviously, The rule to make D::D(D&&) have a potentially-throwing exception specification is neither the first bullet nor the third bullet. For the first rule, the selected constructor to initialize base subobject of type B is B(B&&, int = (throw Y(), 0)) noexcept, which is declared to have a non-throwing exception specification. The third rule is for default constructor. So only the second rule applies to this case.
However, D::D(D&&) shouldn't have a potentially-throwing exception specification except that the expression throw Y() is considered as a subexpression of D::D(D&&).
The rule which define the immediate subexpression is as following:
The immediate subexpressions of an expression e are
the constituent expressions of e's operands
any function call that e implicitly invokes,
if e is a lambda-expression, the initialization of the entities captured by copy and the constituent expressions of the initializer of the init-captures,
if e is a function call or implicitly invokes a function, the constituent expressions of each default argument used in the call, or
if e creates an aggregate object, the constituent expressions of each default member initializer ([class.mem]) used in the initialization.
A subexpression of an expression e is an immediate subexpression of e or a subexpression of an immediate subexpression of e.
The easy way to understand the rule for subexpression is that it works recursively, that is,
immediate subexpression of immediate subexpression... of immediate subexpression of e is a subexpression of e.
I agree the expression throw Y() is a subexpression of function B(B&&, int = (throw Y(), 0)) noexcept due to the fourth bullet. However, I don't know whether B(B&&, int = (throw Y(), 0)) noexcept is considered as an implicitly invoked function which is invoked by expression D::D(D&&), which seems to obey the second bullet. if it is that, please consider the following code:
class Test{
Test(){}
~Test(){}
};
void func(){
Test t{} // implicitly invoke the defautl constructor of `Test`
// would implicitly invoke the destructor of `Test`
}
int main(){
func();
}
So, as I write in the comment, Is the constructor and the destructor of Test is considered as subexpressions of expression func()? If it's not, how to interpret the wording a subexpression of such an initialization? So, my questions are:
Q1:
In the second example, Is the implicitly invoked constructor or destructor be considered as a subexpression of expression func()?
Q2:
If the answer to the first question is no, then how to interpret a subexpression of such an initialization?
In [except.spec]/7.2, specifically the wording "a subexpression of such an initialization", what is "such an initialization"? The answer is that it must refer to an initialization described in p7.1:
a constructor selected by overload resolution in the implicit definition of the constructor for class X to initialize a potentially constructed subobject, or
It doesn't refer to the initialization of X. The text at the beginning of [except.spec]/7 only refers to a "constructor" of X, not the "initialization" of X. The natural way to read p7.2 is that "such an initialization" refers to the only preceding mention of initialization, which is in p7.1.
So the issue here, in applying [except.spec]/7.2, is not whether the constituent expressions of the default arguments of B's move constructor are subexpressions of the D initialization, but rather whether they are subexpressions of the B initialization, and the answer is that they are.
Although the above explanation should answer your main question, I will also say that I don't think the constructor of B is considered "implicitly invoked" by the constructor of D for the purposes of [intro.execution]/10. If it were, then it would mean that the initialization of the B subobject is a subexpression of the initialization of D. Instead, I believe we should consider the initialization of the B subobject as a full-expression under [intro.execution]/12.3:
A full-expression is [...] an init-declarator (Clause 11) or a mem-initializer (15.6.2), including the constituent expressions of the
initializer, [...]
Although the wording is not clear on this, I believe the initialization of the B subobject is considered to be done by a mem-initializer for the purposes of [intro.execution]. [class.copy.ctor]/14, which defines the behaviour of a defaulted move constructor, does not explicitly say that bases and members are initialized as if by a mem-initializer. However, it would be strange if a defaulted definition of a move constructor had a different subexpression hierarchy from the corresponding user-defined constructor.
If we treat the implicit call to the base class constructor as not being a mem-initializer, but rather a "function call that e implicitly invokes" under [intro.execution]/10.2, it would mean that the former is not a full-expression, and there is no point for destruction of temporaries at the end of it. It would be really strange if this were the case: it would mean temporaries created during the execution of a defaulted move constructor are destroyed at different times than temporaries created during the execution of an equivalent user-provided move constructor. A simple experiment on Godbolt reassures me that GCC and Clang do not take such a strange interpretation.
In your second example, the expression func() does not implicitly invoke anything. Functions that are invoked in the body of func() don't count. The point about implicit invocations includes such things as the destructors of temporaries at the end of a full-expression, constructors called to materialize temporary objects, constructors and conversion operators invoked by implicit conversions required by an expression, and so on.
For the first rule, the selected constructor to initialize base sub-object of type B is B (B&&, int = (throw Y(), 0)) noexcept, which is declared to have a non-throwing exception specification. This means that the constructor for B will not throw when called. However, before D calls B, it must generate the 2nd argument from its default value, which will throw. Accordingly, D will throw not because of B but because of the default parameter, which is executed outside B.
In order to see what a subexpression of an initialisation is, you need to consider the code generated by the compiler. Your call of func() does not construct an object of type T in the scope of the call, in that nothing gets injected into the scope of main by the compiler. The object is constructed in the scope of func and that does not count.
Consider the following example:
class X;
void f(const X &);
void g()
{
X x;
f({x});
}
Does standard require that an implementation ignored curly braces in that case? Without any optimization involved. If yes, than since which version?
On a first glance, it looks like by rules there should be a temporary created - completely unnecessary, of course, but still. Looking at list initialization I cannot find anything relevant. X is not an aggregate here.
Both GCC and Clang, even with -O0, produce code without temporary created - even if an X copy constructor has observable side-effects and even if X has X(std::initializer_list<X>) constructor.
The initialization of X const &x (the argument of f) in f({x}) is list initialization in a copy initialization context, by [dcl.init]/15. Thus, we can drop the function and just ask what this means:
int main() {
X x;
X const &y = {x}; // still copy list initialization
}
Now, the first clause in [dcl.init.list] to apply to this is [dcl.init.list]/3.9, which states that you basically just drop the braces.
... if the initializer list has a single element of type E and either T [here X const&] is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization); ....
X const& is in fact a reference type, but its referenced type X const is indeed related to the initializer's type, X, so the clause still applies. Now we just have
int main() {
X x;
X const &y = x; // (non-list/"plain") copy-initialization
}
and of course that doesn't call X's constructor (by [dcl.init.ref]/5.1).
Note that the above quote appears slightly reworded on your cppreference page, too:
... (if T is not a class type), if the braced-init-list has only one element and either T isn't a reference type or is a reference type whose referenced type is same as or is a base class of the type of the element, T is direct-initialized (in direct-list-initialization) or copy-initialized (in copy-list-initialization), ....
Perhaps the "T isn't a reference type" or "T is not a class type" made this fly under the radar, but this is the clause you were looking for, since a) a reference type is indeed not a class type and b) the "or ..." in the preconditions makes it apply. Judging by the lack of versioning boxes, this behavior would be as old as list initialization itself: since C++11.
Where in the C++14 Standard, does it prohibit the declaration of object a below?
class A{ int i = 1; public: A():i{1}{} };
int main()
{
constexpr A a{};
}
See live example
Note that I highlighted the word declaration, because I don't think bullet points (2.7.2) or (2.7.3), in §5.19[expr.const]p2 is an answer for the question.
[dcl.constexpr]p9:
A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.19). [...]
The error you're getting now is because your type is not a literal type. Your type is not a literal type because it does have a custom constructor, but doesn't have any constexpr constructor. The wording in the error message is rather clear about the exact requirements.
If you add a constexpr constructor (but not the default constructor), the error message changes:
class A{ int i = 1; public: A():i{1}{} constexpr A(int){} };
int main()
{
constexpr A a{};
}
Now the error message becomes
error: call to non-constexpr function ‘A::A()’
constexpr A a{};
This is the second part I bolded: it's not the initialiser that has to be a constant expression. You're right, your initialiser isn't an expression at all. It's the constructor call that must be a constant expression, and although it isn't expressed explicitly in the source code, it is an expression nonetheless. This is covered in [expr.const] rather clearly:
an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor (12.4) [...]
to which you already refer in your question.
Well, your default constructor is not constexpr. Therefore, you cannot create a default constructed constexpr object.
I was compiling a C++ program in Cygwin using g++ and I had a class whose constructor had no arguments. I had the lines:
MyClass myObj();
myObj.function1();
And when trying to compile it, I got the message:
error: request for member 'function1' in 'myObj', which is of non-class type 'MyClass ()()'
After a little research, I found that the fix was to change that first line to
MyClass myObj;
I could swear I've done empty constructor declarations with parentheses in C++ before. Is this probably a limitation of the compiler I'm using or does the language standard really say don't use parentheses for a constructor without arguments?
Although MyClass myObj(); could be parsed as an object definition with an empty initializer or a function declaration the language standard specifies that the ambiguity is always resolved in favour of the function declaration. An empty parentheses initializer is allowed in other contexts e.g. in a new expression or constructing a value-initialized temporary.
This is called the Most Vexing Parse issue. When the parser sees
MyClass myObj();
It thinks you are declaring a function called myObj that has no parameters and returns a MyClass.
To get around it, use:
MyClass myObj;
I found this in the C++ standard (§8.5.8):
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
[Note: since () is not permitted by
the syntax for initializer,
X a ();
is not the declaration of an object of class X, but the
declaration of a function taking no
argument and returning an X. The form
() is permitted in certain other
initialization contexts (5.3.4, 5.2.3,
12.6.2). —end note ]
This is a fairly well-known issue and isn't compiler dependent. Essentially, you were declaring a function returning type MyObj. Not surprisingly, you couldn't call its constructor. See the C++ faq lite for a good explanation.
MyClass myObj();
That's parsed as a function declaration. The function is called myObj, takes no arguments and returns a MyClass object. I've never seen a compiler accepting that. On the other hand, MyClass* myPtr = new MyClass(); is acceptable, and may be that got you confused?
Your line makes the compiler think you are declaring a function named myObj which takes no arguments and returns a MyClass. This ambiguity resolution is indeed annoying.
The standard does not require parentheses.
int* x = new int;
is legal syntax.
In your case myclass myobj(); is a function prototype. Whereas myclass myobj; is a variable.