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.
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.
Recently, I asked this question where one of the answers says:
There's no such thing as "implicit this parameter" in the standard. The standard calls it an "implicit object parameter".
Then someone commented that:
There's no such thing as "implicit this parameter" in the standard." seems wrong. From expr.call#4: "If the function is a non-static member function, the this parameter of the function shall be initialized with a pointer to the object of the call, converted as if by an explicit type conversion."
Seeing the above comment i think that the answer is technically incorrect because the answer said that "There's no such thing as "implicit this parameter" in the standard." while the standard clearly talks about the this parameter.
So how to interpret this further (pun intended)? I mean, it seems that the standard makes a distinction between the non-static member function and a constructor in the context of this parameter. For example, the standard says that for a non-static member function, the this parameter of the function shall be initialized with a pointer to the object of the call converted as if by an explicit type conversion. But the standard doesn't say the same for constructors. So why does the standard makes this distinction? I mean why doesn't the standard says that constructors also have an this parameter that get initialized by the passed argument just like for non-static member functions. This again leads to the deeper question that if there is no this parameter in the constructor unlike non-static member function, then how are we able to use this inside the constructor. For example, we know that we can write this->p = 0 inside the constructor as well as inside a non-static member function, where p is a data member. But in case of non-static member function, this is a parameter of that particular member function so this->p makes sense. But in case of constructor this is not a parameter, so how are we able to use this->p inside the constructor.
Originally, by reading the answers here, I thought that the implicit this parameter is an implementation detail. But after reading expr.call#4 it seems that it is not an implementation detail.
If you think this is some sort of implicit parameter, type in this code:
#include <iostream>
struct SimpleThing {
int xyzzy;
SimpleThing(): xyzzy(42) {}
void print(int plugh, const int twisty) {
std::cout << xyzzy << '\n';
std::cout << plugh << '\n';
std::cout << twisty << '\n';
xyzzy = 0;
plugh = 0;
twisty = 0;
this = 0;
}
};
int main() {
SimpleThing thing;
thing.print(7, 99);
}
Then examine the errors you get:
prog.cpp: In member function ‘void SimpleThing::print(int, int)’:
prog.cpp:12:16: error: assignment of read-only parameter ‘twisty’
12 | twisty = 0;
| ~~~~~~~^~~
prog.cpp:13:16: error: lvalue required as left operand of assignment
13 | this = 0;
| ^
Note that the first two assignments work because they are modifiable variables. The third fails because it is, of course, (non-modifiable) const.
The attempted assignment to this doesn't look like any sort of "can't write to some sort of variable" diagnostic because it actually isn't.
The this keyword is a special marker inside non-static member functions (and constructors/destructors) that is translated into the address of the object being worked upon. While it may be passed as a hidden parameter, that is very much an implementation detail with which the standard does not concern itself.
The controlling section in the C++20 standard is in [class.this]:
In the body of a non-static member function, the keyword this is a prvalue whose value is the address of the object for which the function is called.
Nowhere in there (the entire section) does it mention that this is some sort of hidden parameter to the call.
And, regarding your question on why there is a distinction between non-static member functions and constructors, I don't believe this distinction involves the existence of this in either case, it instead has to do with the qualification of the type of this. It's existence in a constructor is undeniable as [class.ctor] states:
During the construction of an object, if the value of the object or any of its subobjects is accessed through a glvalue that is not obtained, directly or indirectly, from the constructor’s this pointer, the value of the object or subobject thus obtained is unspecified.
In other words, I see your quote:
If the function is a non-static member function, the this parameter of the function is initialized with a pointer to the object of the call, converted as if by an explicit type conversion.
as specifying only the qualification of this, something that the constructor doesn't need.
There is no discussion of cv-qualified conversion for constructors as there is for other member functions because you can't actually create a cv-qualified constructor. It would be rather useless if your constructor were not allowed to set any member variables, for example :-)
While constructors can be used to create cv-qualified objects, the constructor itself is not cv-qualified. This is covered at the end of [class.this]:
Constructors and destructors shall not be declared const, volatile or const volatile. [Note: However, these functions can be invoked to create and destroy objects with cv-qualified types - end note]
And further in [class.ctor]:
A constructor can be invoked for a const, volatile or const volatile object. Const and volatile semantics are not applied on an object under construction. They come into effect when the
constructor for the most derived object ends.
To be honest, I think WG21 would be better off going through the next iteration and replacing things like "the this parameter of the function" with a phrase that does not mention parameters at all (such as "the this property".
Here's a quotation from this Draft C++17 Standard (bolding for emphasis, and to answer the question, is mine):
10.3.3 The using declaration [namespace.udecl]
…
16
For the purpose of forming a set of candidates during overload
resolution, the functions that are introduced by a using-declaration
into a derived class are treated as though they were members of the
derived class. In particular, the implicit this parameter shall
be treated as if it were a pointer to the derived class rather than to
the base class. This has no effect on the type of the function, and in
all other respects the function remains a member of the base class.
Likewise, constructors that are introduced by a using-declaration
are treated as though they were constructors of the derived class when
looking up the constructors of the derived class …
However I should add that the cited paragraph doesn't seem to be present in this later Draft Standard. In fact, that (later) Standard seems to use the phrase, "implicit object parameter," in similar clauses.
So, maybe you should add a specific version tag to your question: c++17 or c++20, as there appears to be a divergence in the use (or not) of the term.
Note that the above citation is the only occurrence of the phrase, "implicit this parameter" in that Draft Standard.
Also, note that both documents I have linked are only Draft versions of the respective Standards, and both come with this cautionary escape-clause:
Note: this is an early draft. It’s known to be incomplet and
incorrekt, and it has lots of bad formatting.
It seems to me that aggregate initialization (of suitable types) is not considered a constructor that you can actually call (except a few cases.)
As an example, if we have a very simple aggregate type:
struct Foo {
int x, y;
};
then this obviously works:
auto p = new Foo {42, 17}; // not "Foo (42, 17)" though...
but this doesn't work on any compiler that I've tested (including latest versions of MSVC, GCC, and Clang):
std::vector<Foo> v;
v.emplace_back(2, 3);
Again, it seems to me that any code that wants to call the constructor for a type T (in this case, the code in vector::emplace_back that forwards the passed arguments to the c'tor of T,) cannot use aggregate initialization simply (it seems) because they use parentheses instead of curly braces!
Why is that? Is it just a missed feature (nobody has proposed/implemented it yet,) or there are deeper reasons? This is a little strange, because aggregate types by definition have no other constructor to make the resolution ambiguous, so the language could have just defined a default aggregate constructor (or something) that would have all the members as defaulted arguments.
Is it just a matter of syntax? If the implementation of vector::emplace_back in the above example had used placement new with curly braces instead of parentheses, would it have worked?
Note: I want to thank those comments who've pointed out the behavior of vector and emplace because their comments will be valuable to those who'll find this question using those keywords, but I also want to point out that those are just examples. I picked the most familiar and concise example, but my point was about explicitly calling the aggregate initializer in any code (or in placement new, more specifically.)
For what it's worth, P0960 "Allow initializing aggregates from a parenthesized list of values" does exactly what it says. It seems to have passed EWG and is on its way into C++20.
aggregate types by definition have no other constructor to make the resolution ambiguous
That is incorrect. All classes have default constructors, as well as copy/move constructors. Even if you = delete them or they are implicitly deleted, they still technically have such constructors (you just can't call them).
C++ being C++, there are naturally corner cases where even P0960 does the "wrong thing", as outlined in the paper:
struct A;
struct C
{
operator A(); //Implicitly convertible to `A`
};
struct A { C c; }; //First member is a `C`
C c2;
A a(c2);
The initialization of a is a case of ambiguity. Two things could happen. You could perform implicit conversion of c2 to an A, then initialize a from the resulting prvalue. Or you could perform aggregate initialization of a by a single value of type C.
P0960 takes the backwards compatible route: if a constructor could be called (under existing rules), then it always takes priority. Parentheses only invoke aggregate initialization if there is no constructor that could have been called.
https://en.cppreference.com/w/cpp/language/aggregate_initialization
Aggregate Initialization is not a constructor.
According to this document, you did not define any constructors and meet the other conditions for Aggregate Initialization. (Refer to the item "class type" in the section "Explanation") That means your code does not call something like automatically generated constructor of signature Foo(int, int) but it is just another feature.
The document says about its effect is:
Each array element, or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.
As vector::emplace_back(Args&&... args) works this way and it cannot find such constructor.
The arguments args... are forwarded to the constructor as std::forward<Args>(args)....
So it does not find such constructor.
Thinking this way, it also makes sense that your code cannot compile auto p = new Foo (42, 17);.
One more example, if you write any kind of constructor(even Foo::Foo() {}), auto p = new Foo {42, 17}; does not work. Because now it does not meet the condition for Aggregate Initialization.
As far as I know Aggregate Initialization also works in C which does not even support constructors.
Here's a good article worth reading.
I was reading this post. The code under attention is the following
struct S {
void func() &;
void func() &&;
};
S s1;
s1.func(); // OK, calls S::func() &
S().func(); // OK, calls S::func() &&
I think I understood what are the reference qualifiers. My question is more basic: what is S()? Is it a (copy) creator? Why is it an rvalue? It seems that in that blog and also in other places it is taken for granted. What am I missing?
Formally it's an explicit cast (functional notation). It creates a temporary object from the (possibly empty) list of arguments. And yes, it does so by doing overload resolution to pick the correct constructor to call. In this case, the default c'tor (which your compiler produces, on account of no other c'tor being declared).
More formally, the explicit cast is an expression whose result is a prvalue (pure rvalue). So when doing overload resolution to pick a member function to call, the rvalue qualified version is preferable.
I imagine the blog skimmed over it because that existed in C++ since time immemorial. And the post's intent was to introduce a new concept, assuming readers already know this about C++.
S() creates a temporary object which is an rvalue. The object is constructed using default constructor. It is destroyed just after the full expression is evaluated.
More generally, one way to think about this syntax is: type name + arguments list passed to the constructor of the object.
In this case S is the type name and the empty parenthesis means there are no arguments for the constructor so the default constructor is chosen.
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.