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









share|improve this question


















  • 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

















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









share|improve this question


















  • 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















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









share|improve this question













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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










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
















  • 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














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.







share|improve this answer























  • 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 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




















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.






share|improve this answer























    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
    });


    }
    });














    draft saved

    draft discarded


















    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.







    share|improve this answer























    • 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 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

















    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.







    share|improve this answer























    • 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 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















    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.







    share|improve this answer














    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.








    share|improve this answer














    share|improve this answer



    share|improve this answer








    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 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




















    • 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 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


















    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














    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.






    share|improve this answer



























      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.






      share|improve this answer

























        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.






        share|improve this answer














        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.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 1 hour ago

























        answered 2 hours ago









        P i

        2,557932




        2,557932






























            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Quarter-circle Tiles

            build a pushdown automaton that recognizes the reverse language of a given pushdown automaton?

            Mont Emei