Why won't this compile without a default constructor?
up vote
7
down vote
favorite
I can do this:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(8);
}
};
Boo(8);
return 0;
}
This will compile fine, my counter result is 21. However when I try to create the Boo object passing the constructor argument instead of an integer literal I get a compile error:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(num); // No default constructor
// exists for Boo
}
};
Boo(8);
return 0;
}
How is a default constructor called in the second example but not in the first example? This is error I get on Visual Studio 2017.
On the online C++ compiler onlineGDB I get the errors:
error: no matching function for call to ‘main()::Boo::Boo()’
if (rand() % num < 7) Boo(num);
^
note: candidate expects 1 argument, 0 provided
c++ constructor default-constructor
|
show 3 more comments
up vote
7
down vote
favorite
I can do this:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(8);
}
};
Boo(8);
return 0;
}
This will compile fine, my counter result is 21. However when I try to create the Boo object passing the constructor argument instead of an integer literal I get a compile error:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(num); // No default constructor
// exists for Boo
}
};
Boo(8);
return 0;
}
How is a default constructor called in the second example but not in the first example? This is error I get on Visual Studio 2017.
On the online C++ compiler onlineGDB I get the errors:
error: no matching function for call to ‘main()::Boo::Boo()’
if (rand() % num < 7) Boo(num);
^
note: candidate expects 1 argument, 0 provided
c++ constructor default-constructor
1
Is there any reason I should not close this as a "most vexing" dupe? And why is it and the answers being upvoted?
– Neil Butterworth
1 hour ago
@NeilButterworth I'm aware of the most vexing parse, but it didn't strike me as a case of it because I was passing local variable to the constructor, and thought that this was not ambiguous because I didn't see it as ambiguous when passing a local variable identifier. user10605163's answer is enlightening as it explains that types or non-types are not used in disambiguation. I don't know anything about the upvotes other than that I upvoted both answers as I found them helpful. You can close this if this is dupe.
– Zebrafish
1 hour ago
I asked because there seems to be a lot of apparently iffy upvoting on the C++ tag just recently.
– Neil Butterworth
1 hour ago
1
@NeilButterworth: "Any problems with these proposals?" Because the most-vexing parse is usually presented as a competition between creating a temporary and declaring a function. This is instead treated as creating a variable. Similar idea, similar resolution, but ultimately a different source.
– Nicol Bolas
51 mins ago
1
@Nicol "Any problems with these proposals?" - um, what? Where?
– Neil Butterworth
33 mins ago
|
show 3 more comments
up vote
7
down vote
favorite
up vote
7
down vote
favorite
I can do this:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(8);
}
};
Boo(8);
return 0;
}
This will compile fine, my counter result is 21. However when I try to create the Boo object passing the constructor argument instead of an integer literal I get a compile error:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(num); // No default constructor
// exists for Boo
}
};
Boo(8);
return 0;
}
How is a default constructor called in the second example but not in the first example? This is error I get on Visual Studio 2017.
On the online C++ compiler onlineGDB I get the errors:
error: no matching function for call to ‘main()::Boo::Boo()’
if (rand() % num < 7) Boo(num);
^
note: candidate expects 1 argument, 0 provided
c++ constructor default-constructor
I can do this:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(8);
}
};
Boo(8);
return 0;
}
This will compile fine, my counter result is 21. However when I try to create the Boo object passing the constructor argument instead of an integer literal I get a compile error:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(num); // No default constructor
// exists for Boo
}
};
Boo(8);
return 0;
}
How is a default constructor called in the second example but not in the first example? This is error I get on Visual Studio 2017.
On the online C++ compiler onlineGDB I get the errors:
error: no matching function for call to ‘main()::Boo::Boo()’
if (rand() % num < 7) Boo(num);
^
note: candidate expects 1 argument, 0 provided
c++ constructor default-constructor
c++ constructor default-constructor
asked 2 hours ago
Zebrafish
3,52211235
3,52211235
1
Is there any reason I should not close this as a "most vexing" dupe? And why is it and the answers being upvoted?
– Neil Butterworth
1 hour ago
@NeilButterworth I'm aware of the most vexing parse, but it didn't strike me as a case of it because I was passing local variable to the constructor, and thought that this was not ambiguous because I didn't see it as ambiguous when passing a local variable identifier. user10605163's answer is enlightening as it explains that types or non-types are not used in disambiguation. I don't know anything about the upvotes other than that I upvoted both answers as I found them helpful. You can close this if this is dupe.
– Zebrafish
1 hour ago
I asked because there seems to be a lot of apparently iffy upvoting on the C++ tag just recently.
– Neil Butterworth
1 hour ago
1
@NeilButterworth: "Any problems with these proposals?" Because the most-vexing parse is usually presented as a competition between creating a temporary and declaring a function. This is instead treated as creating a variable. Similar idea, similar resolution, but ultimately a different source.
– Nicol Bolas
51 mins ago
1
@Nicol "Any problems with these proposals?" - um, what? Where?
– Neil Butterworth
33 mins ago
|
show 3 more comments
1
Is there any reason I should not close this as a "most vexing" dupe? And why is it and the answers being upvoted?
– Neil Butterworth
1 hour ago
@NeilButterworth I'm aware of the most vexing parse, but it didn't strike me as a case of it because I was passing local variable to the constructor, and thought that this was not ambiguous because I didn't see it as ambiguous when passing a local variable identifier. user10605163's answer is enlightening as it explains that types or non-types are not used in disambiguation. I don't know anything about the upvotes other than that I upvoted both answers as I found them helpful. You can close this if this is dupe.
– Zebrafish
1 hour ago
I asked because there seems to be a lot of apparently iffy upvoting on the C++ tag just recently.
– Neil Butterworth
1 hour ago
1
@NeilButterworth: "Any problems with these proposals?" Because the most-vexing parse is usually presented as a competition between creating a temporary and declaring a function. This is instead treated as creating a variable. Similar idea, similar resolution, but ultimately a different source.
– Nicol Bolas
51 mins ago
1
@Nicol "Any problems with these proposals?" - um, what? Where?
– Neil Butterworth
33 mins ago
1
1
Is there any reason I should not close this as a "most vexing" dupe? And why is it and the answers being upvoted?
– Neil Butterworth
1 hour ago
Is there any reason I should not close this as a "most vexing" dupe? And why is it and the answers being upvoted?
– Neil Butterworth
1 hour ago
@NeilButterworth I'm aware of the most vexing parse, but it didn't strike me as a case of it because I was passing local variable to the constructor, and thought that this was not ambiguous because I didn't see it as ambiguous when passing a local variable identifier. user10605163's answer is enlightening as it explains that types or non-types are not used in disambiguation. I don't know anything about the upvotes other than that I upvoted both answers as I found them helpful. You can close this if this is dupe.
– Zebrafish
1 hour ago
@NeilButterworth I'm aware of the most vexing parse, but it didn't strike me as a case of it because I was passing local variable to the constructor, and thought that this was not ambiguous because I didn't see it as ambiguous when passing a local variable identifier. user10605163's answer is enlightening as it explains that types or non-types are not used in disambiguation. I don't know anything about the upvotes other than that I upvoted both answers as I found them helpful. You can close this if this is dupe.
– Zebrafish
1 hour ago
I asked because there seems to be a lot of apparently iffy upvoting on the C++ tag just recently.
– Neil Butterworth
1 hour ago
I asked because there seems to be a lot of apparently iffy upvoting on the C++ tag just recently.
– Neil Butterworth
1 hour ago
1
1
@NeilButterworth: "Any problems with these proposals?" Because the most-vexing parse is usually presented as a competition between creating a temporary and declaring a function. This is instead treated as creating a variable. Similar idea, similar resolution, but ultimately a different source.
– Nicol Bolas
51 mins ago
@NeilButterworth: "Any problems with these proposals?" Because the most-vexing parse is usually presented as a competition between creating a temporary and declaring a function. This is instead treated as creating a variable. Similar idea, similar resolution, but ultimately a different source.
– Nicol Bolas
51 mins ago
1
1
@Nicol "Any problems with these proposals?" - um, what? Where?
– Neil Butterworth
33 mins ago
@Nicol "Any problems with these proposals?" - um, what? Where?
– Neil Butterworth
33 mins ago
|
show 3 more comments
2 Answers
2
active
oldest
votes
up vote
12
down vote
Clang gives this warning message:
<source>:12:16: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
Boo(num); // No default constructor
^~~~~
This is a most vexing parse issue. The compiler has to decide whether you want to call Boo
with num
as argument or whether you are writing a declaration Boo num;
with extra parantheses around num
. If both is possible the standard requires to assume a declaration.
If it is parsed as declaration, then Boo num;
would call the default constructor (the constructor without arguments), which isn't declared either by you or implicitly.
This is not an issue with Boo(8);
, because 8
cannot be a variable's identifier, so it is parsed as a call creating a Boo
temporary with 8
as argument to the constructor, thereby not calling the default constructor (which is not declared), but the one you defined manually.
You can disambiguate this from a declaration by either using Boo{num};
instead of Boo(num);
(because {}
around the declarator is not allowed.), by making the temporary a named variable, e.g. Boo temp(num);
, or by putting it as an operand in another expression, e.g. (Boo(num));
, (void)Boo(num);
, etc.
In any case it doesn't seem a good idea to misuse temporary object creation for something that should be a normal (member) function call.
This happens even though the declaration would be ill-formed as it changes the type of num
, because of [stmt.ambig]/3:
The disambiguation is purely syntactic; that is, the meaning of the
names occurring in such a statement, beyond whether they are
type-names or not, is not generally used in or changed by the
disambiguation.
[...]
Disambiguation precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration.
Thanks for your answer, that makes sense if it's a type of vexing parse problem. What I don't get is that num is a local variable, and don't see how this could be mistaken for a type, which is usually when the vexing parse problem comes up I think.
– Zebrafish
2 hours ago
@Zebrafish I added the paragraph of the standard which seems to be responsible. It is not mistaken for a type. It is used as a variable name and the only confusion seems to be that the name is already declared in the scope with different type.
– user10605163
2 hours ago
I see. So it seems it allows Boo(8) not so much because 8 is unambiguous with respect to an argument, but more because 8 can't be the name of an identifier for an object, if I understand right.
– Zebrafish
2 hours ago
Yes that is correct. The issue also does not exist if the temporaryBoo(...)
is used inside another expression, because then it cannot be a declaration statement. You are only seeing this weird case because you are creating unnamed temporaries and then immediately discarding them again. Simply don't do that.
– user10605163
1 hour ago
add a comment |
up vote
6
down vote
This is known as the "most vexing parse" (The term was used by Scott Meyers in Effective STL).
Boo(num)
is not a call to the constructor. Clang gives a good warning to see:
<source>:12:38: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
So you declared a Boo variable with name num, which needs the default constructor.
For Boo(8)
this cannot happen, as the parser can be sure this is not a decleration and calls the constructor Boo(int)
.
The c++ standard, section 8.2, requires the compiler to assume this is a function declaration
C++ Standard 8.2 [dcl.ambig.res]
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in [stmt.ambig] can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in [stmt.ambig], the resolution is to consider any construct that could possibly be a declaration a declaration. [ Note: A declaration can be explicitly disambiguated by a nonfunction-style cast, by an = to indicate initialization or by removing the redundant parentheses around the parameter name. — end note ]
[ Example:
struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
— end example ]
By the way: You can disambiguate by using enclosing parentheses:
if (rand() % num < 7) (Boo(num));
or in my opinion better, use the new uniform initialization syntax
if (rand() % num < 7) Boo{num};
Which will then compile see here.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53806896%2fwhy-wont-this-compile-without-a-default-constructor%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
12
down vote
Clang gives this warning message:
<source>:12:16: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
Boo(num); // No default constructor
^~~~~
This is a most vexing parse issue. The compiler has to decide whether you want to call Boo
with num
as argument or whether you are writing a declaration Boo num;
with extra parantheses around num
. If both is possible the standard requires to assume a declaration.
If it is parsed as declaration, then Boo num;
would call the default constructor (the constructor without arguments), which isn't declared either by you or implicitly.
This is not an issue with Boo(8);
, because 8
cannot be a variable's identifier, so it is parsed as a call creating a Boo
temporary with 8
as argument to the constructor, thereby not calling the default constructor (which is not declared), but the one you defined manually.
You can disambiguate this from a declaration by either using Boo{num};
instead of Boo(num);
(because {}
around the declarator is not allowed.), by making the temporary a named variable, e.g. Boo temp(num);
, or by putting it as an operand in another expression, e.g. (Boo(num));
, (void)Boo(num);
, etc.
In any case it doesn't seem a good idea to misuse temporary object creation for something that should be a normal (member) function call.
This happens even though the declaration would be ill-formed as it changes the type of num
, because of [stmt.ambig]/3:
The disambiguation is purely syntactic; that is, the meaning of the
names occurring in such a statement, beyond whether they are
type-names or not, is not generally used in or changed by the
disambiguation.
[...]
Disambiguation precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration.
Thanks for your answer, that makes sense if it's a type of vexing parse problem. What I don't get is that num is a local variable, and don't see how this could be mistaken for a type, which is usually when the vexing parse problem comes up I think.
– Zebrafish
2 hours ago
@Zebrafish I added the paragraph of the standard which seems to be responsible. It is not mistaken for a type. It is used as a variable name and the only confusion seems to be that the name is already declared in the scope with different type.
– user10605163
2 hours ago
I see. So it seems it allows Boo(8) not so much because 8 is unambiguous with respect to an argument, but more because 8 can't be the name of an identifier for an object, if I understand right.
– Zebrafish
2 hours ago
Yes that is correct. The issue also does not exist if the temporaryBoo(...)
is used inside another expression, because then it cannot be a declaration statement. You are only seeing this weird case because you are creating unnamed temporaries and then immediately discarding them again. Simply don't do that.
– user10605163
1 hour ago
add a comment |
up vote
12
down vote
Clang gives this warning message:
<source>:12:16: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
Boo(num); // No default constructor
^~~~~
This is a most vexing parse issue. The compiler has to decide whether you want to call Boo
with num
as argument or whether you are writing a declaration Boo num;
with extra parantheses around num
. If both is possible the standard requires to assume a declaration.
If it is parsed as declaration, then Boo num;
would call the default constructor (the constructor without arguments), which isn't declared either by you or implicitly.
This is not an issue with Boo(8);
, because 8
cannot be a variable's identifier, so it is parsed as a call creating a Boo
temporary with 8
as argument to the constructor, thereby not calling the default constructor (which is not declared), but the one you defined manually.
You can disambiguate this from a declaration by either using Boo{num};
instead of Boo(num);
(because {}
around the declarator is not allowed.), by making the temporary a named variable, e.g. Boo temp(num);
, or by putting it as an operand in another expression, e.g. (Boo(num));
, (void)Boo(num);
, etc.
In any case it doesn't seem a good idea to misuse temporary object creation for something that should be a normal (member) function call.
This happens even though the declaration would be ill-formed as it changes the type of num
, because of [stmt.ambig]/3:
The disambiguation is purely syntactic; that is, the meaning of the
names occurring in such a statement, beyond whether they are
type-names or not, is not generally used in or changed by the
disambiguation.
[...]
Disambiguation precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration.
Thanks for your answer, that makes sense if it's a type of vexing parse problem. What I don't get is that num is a local variable, and don't see how this could be mistaken for a type, which is usually when the vexing parse problem comes up I think.
– Zebrafish
2 hours ago
@Zebrafish I added the paragraph of the standard which seems to be responsible. It is not mistaken for a type. It is used as a variable name and the only confusion seems to be that the name is already declared in the scope with different type.
– user10605163
2 hours ago
I see. So it seems it allows Boo(8) not so much because 8 is unambiguous with respect to an argument, but more because 8 can't be the name of an identifier for an object, if I understand right.
– Zebrafish
2 hours ago
Yes that is correct. The issue also does not exist if the temporaryBoo(...)
is used inside another expression, because then it cannot be a declaration statement. You are only seeing this weird case because you are creating unnamed temporaries and then immediately discarding them again. Simply don't do that.
– user10605163
1 hour ago
add a comment |
up vote
12
down vote
up vote
12
down vote
Clang gives this warning message:
<source>:12:16: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
Boo(num); // No default constructor
^~~~~
This is a most vexing parse issue. The compiler has to decide whether you want to call Boo
with num
as argument or whether you are writing a declaration Boo num;
with extra parantheses around num
. If both is possible the standard requires to assume a declaration.
If it is parsed as declaration, then Boo num;
would call the default constructor (the constructor without arguments), which isn't declared either by you or implicitly.
This is not an issue with Boo(8);
, because 8
cannot be a variable's identifier, so it is parsed as a call creating a Boo
temporary with 8
as argument to the constructor, thereby not calling the default constructor (which is not declared), but the one you defined manually.
You can disambiguate this from a declaration by either using Boo{num};
instead of Boo(num);
(because {}
around the declarator is not allowed.), by making the temporary a named variable, e.g. Boo temp(num);
, or by putting it as an operand in another expression, e.g. (Boo(num));
, (void)Boo(num);
, etc.
In any case it doesn't seem a good idea to misuse temporary object creation for something that should be a normal (member) function call.
This happens even though the declaration would be ill-formed as it changes the type of num
, because of [stmt.ambig]/3:
The disambiguation is purely syntactic; that is, the meaning of the
names occurring in such a statement, beyond whether they are
type-names or not, is not generally used in or changed by the
disambiguation.
[...]
Disambiguation precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration.
Clang gives this warning message:
<source>:12:16: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
Boo(num); // No default constructor
^~~~~
This is a most vexing parse issue. The compiler has to decide whether you want to call Boo
with num
as argument or whether you are writing a declaration Boo num;
with extra parantheses around num
. If both is possible the standard requires to assume a declaration.
If it is parsed as declaration, then Boo num;
would call the default constructor (the constructor without arguments), which isn't declared either by you or implicitly.
This is not an issue with Boo(8);
, because 8
cannot be a variable's identifier, so it is parsed as a call creating a Boo
temporary with 8
as argument to the constructor, thereby not calling the default constructor (which is not declared), but the one you defined manually.
You can disambiguate this from a declaration by either using Boo{num};
instead of Boo(num);
(because {}
around the declarator is not allowed.), by making the temporary a named variable, e.g. Boo temp(num);
, or by putting it as an operand in another expression, e.g. (Boo(num));
, (void)Boo(num);
, etc.
In any case it doesn't seem a good idea to misuse temporary object creation for something that should be a normal (member) function call.
This happens even though the declaration would be ill-formed as it changes the type of num
, because of [stmt.ambig]/3:
The disambiguation is purely syntactic; that is, the meaning of the
names occurring in such a statement, beyond whether they are
type-names or not, is not generally used in or changed by the
disambiguation.
[...]
Disambiguation precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration.
edited 1 hour ago
answered 2 hours ago
user10605163
1,729218
1,729218
Thanks for your answer, that makes sense if it's a type of vexing parse problem. What I don't get is that num is a local variable, and don't see how this could be mistaken for a type, which is usually when the vexing parse problem comes up I think.
– Zebrafish
2 hours ago
@Zebrafish I added the paragraph of the standard which seems to be responsible. It is not mistaken for a type. It is used as a variable name and the only confusion seems to be that the name is already declared in the scope with different type.
– user10605163
2 hours ago
I see. So it seems it allows Boo(8) not so much because 8 is unambiguous with respect to an argument, but more because 8 can't be the name of an identifier for an object, if I understand right.
– Zebrafish
2 hours ago
Yes that is correct. The issue also does not exist if the temporaryBoo(...)
is used inside another expression, because then it cannot be a declaration statement. You are only seeing this weird case because you are creating unnamed temporaries and then immediately discarding them again. Simply don't do that.
– user10605163
1 hour ago
add a comment |
Thanks for your answer, that makes sense if it's a type of vexing parse problem. What I don't get is that num is a local variable, and don't see how this could be mistaken for a type, which is usually when the vexing parse problem comes up I think.
– Zebrafish
2 hours ago
@Zebrafish I added the paragraph of the standard which seems to be responsible. It is not mistaken for a type. It is used as a variable name and the only confusion seems to be that the name is already declared in the scope with different type.
– user10605163
2 hours ago
I see. So it seems it allows Boo(8) not so much because 8 is unambiguous with respect to an argument, but more because 8 can't be the name of an identifier for an object, if I understand right.
– Zebrafish
2 hours ago
Yes that is correct. The issue also does not exist if the temporaryBoo(...)
is used inside another expression, because then it cannot be a declaration statement. You are only seeing this weird case because you are creating unnamed temporaries and then immediately discarding them again. Simply don't do that.
– user10605163
1 hour ago
Thanks for your answer, that makes sense if it's a type of vexing parse problem. What I don't get is that num is a local variable, and don't see how this could be mistaken for a type, which is usually when the vexing parse problem comes up I think.
– Zebrafish
2 hours ago
Thanks for your answer, that makes sense if it's a type of vexing parse problem. What I don't get is that num is a local variable, and don't see how this could be mistaken for a type, which is usually when the vexing parse problem comes up I think.
– Zebrafish
2 hours ago
@Zebrafish I added the paragraph of the standard which seems to be responsible. It is not mistaken for a type. It is used as a variable name and the only confusion seems to be that the name is already declared in the scope with different type.
– user10605163
2 hours ago
@Zebrafish I added the paragraph of the standard which seems to be responsible. It is not mistaken for a type. It is used as a variable name and the only confusion seems to be that the name is already declared in the scope with different type.
– user10605163
2 hours ago
I see. So it seems it allows Boo(8) not so much because 8 is unambiguous with respect to an argument, but more because 8 can't be the name of an identifier for an object, if I understand right.
– Zebrafish
2 hours ago
I see. So it seems it allows Boo(8) not so much because 8 is unambiguous with respect to an argument, but more because 8 can't be the name of an identifier for an object, if I understand right.
– Zebrafish
2 hours ago
Yes that is correct. The issue also does not exist if the temporary
Boo(...)
is used inside another expression, because then it cannot be a declaration statement. You are only seeing this weird case because you are creating unnamed temporaries and then immediately discarding them again. Simply don't do that.– user10605163
1 hour ago
Yes that is correct. The issue also does not exist if the temporary
Boo(...)
is used inside another expression, because then it cannot be a declaration statement. You are only seeing this weird case because you are creating unnamed temporaries and then immediately discarding them again. Simply don't do that.– user10605163
1 hour ago
add a comment |
up vote
6
down vote
This is known as the "most vexing parse" (The term was used by Scott Meyers in Effective STL).
Boo(num)
is not a call to the constructor. Clang gives a good warning to see:
<source>:12:38: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
So you declared a Boo variable with name num, which needs the default constructor.
For Boo(8)
this cannot happen, as the parser can be sure this is not a decleration and calls the constructor Boo(int)
.
The c++ standard, section 8.2, requires the compiler to assume this is a function declaration
C++ Standard 8.2 [dcl.ambig.res]
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in [stmt.ambig] can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in [stmt.ambig], the resolution is to consider any construct that could possibly be a declaration a declaration. [ Note: A declaration can be explicitly disambiguated by a nonfunction-style cast, by an = to indicate initialization or by removing the redundant parentheses around the parameter name. — end note ]
[ Example:
struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
— end example ]
By the way: You can disambiguate by using enclosing parentheses:
if (rand() % num < 7) (Boo(num));
or in my opinion better, use the new uniform initialization syntax
if (rand() % num < 7) Boo{num};
Which will then compile see here.
add a comment |
up vote
6
down vote
This is known as the "most vexing parse" (The term was used by Scott Meyers in Effective STL).
Boo(num)
is not a call to the constructor. Clang gives a good warning to see:
<source>:12:38: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
So you declared a Boo variable with name num, which needs the default constructor.
For Boo(8)
this cannot happen, as the parser can be sure this is not a decleration and calls the constructor Boo(int)
.
The c++ standard, section 8.2, requires the compiler to assume this is a function declaration
C++ Standard 8.2 [dcl.ambig.res]
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in [stmt.ambig] can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in [stmt.ambig], the resolution is to consider any construct that could possibly be a declaration a declaration. [ Note: A declaration can be explicitly disambiguated by a nonfunction-style cast, by an = to indicate initialization or by removing the redundant parentheses around the parameter name. — end note ]
[ Example:
struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
— end example ]
By the way: You can disambiguate by using enclosing parentheses:
if (rand() % num < 7) (Boo(num));
or in my opinion better, use the new uniform initialization syntax
if (rand() % num < 7) Boo{num};
Which will then compile see here.
add a comment |
up vote
6
down vote
up vote
6
down vote
This is known as the "most vexing parse" (The term was used by Scott Meyers in Effective STL).
Boo(num)
is not a call to the constructor. Clang gives a good warning to see:
<source>:12:38: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
So you declared a Boo variable with name num, which needs the default constructor.
For Boo(8)
this cannot happen, as the parser can be sure this is not a decleration and calls the constructor Boo(int)
.
The c++ standard, section 8.2, requires the compiler to assume this is a function declaration
C++ Standard 8.2 [dcl.ambig.res]
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in [stmt.ambig] can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in [stmt.ambig], the resolution is to consider any construct that could possibly be a declaration a declaration. [ Note: A declaration can be explicitly disambiguated by a nonfunction-style cast, by an = to indicate initialization or by removing the redundant parentheses around the parameter name. — end note ]
[ Example:
struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
— end example ]
By the way: You can disambiguate by using enclosing parentheses:
if (rand() % num < 7) (Boo(num));
or in my opinion better, use the new uniform initialization syntax
if (rand() % num < 7) Boo{num};
Which will then compile see here.
This is known as the "most vexing parse" (The term was used by Scott Meyers in Effective STL).
Boo(num)
is not a call to the constructor. Clang gives a good warning to see:
<source>:12:38: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
So you declared a Boo variable with name num, which needs the default constructor.
For Boo(8)
this cannot happen, as the parser can be sure this is not a decleration and calls the constructor Boo(int)
.
The c++ standard, section 8.2, requires the compiler to assume this is a function declaration
C++ Standard 8.2 [dcl.ambig.res]
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in [stmt.ambig] can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in [stmt.ambig], the resolution is to consider any construct that could possibly be a declaration a declaration. [ Note: A declaration can be explicitly disambiguated by a nonfunction-style cast, by an = to indicate initialization or by removing the redundant parentheses around the parameter name. — end note ]
[ Example:
struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
— end example ]
By the way: You can disambiguate by using enclosing parentheses:
if (rand() % num < 7) (Boo(num));
or in my opinion better, use the new uniform initialization syntax
if (rand() % num < 7) Boo{num};
Which will then compile see here.
edited 1 hour ago
answered 2 hours ago
P i
2,557932
2,557932
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53806896%2fwhy-wont-this-compile-without-a-default-constructor%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Is there any reason I should not close this as a "most vexing" dupe? And why is it and the answers being upvoted?
– Neil Butterworth
1 hour ago
@NeilButterworth I'm aware of the most vexing parse, but it didn't strike me as a case of it because I was passing local variable to the constructor, and thought that this was not ambiguous because I didn't see it as ambiguous when passing a local variable identifier. user10605163's answer is enlightening as it explains that types or non-types are not used in disambiguation. I don't know anything about the upvotes other than that I upvoted both answers as I found them helpful. You can close this if this is dupe.
– Zebrafish
1 hour ago
I asked because there seems to be a lot of apparently iffy upvoting on the C++ tag just recently.
– Neil Butterworth
1 hour ago
1
@NeilButterworth: "Any problems with these proposals?" Because the most-vexing parse is usually presented as a competition between creating a temporary and declaring a function. This is instead treated as creating a variable. Similar idea, similar resolution, but ultimately a different source.
– Nicol Bolas
51 mins ago
1
@Nicol "Any problems with these proposals?" - um, what? Where?
– Neil Butterworth
33 mins ago