c++syntaxlanguage-lawyerexplicit

What is the purpose of the last sentence in [dcl.fct.spec]/4?


[dcl.fct.spec]/4:

In an explicit-specifier, the constant-expression, if supplied, shall be a contextually converted constant expression of type bool ([expr.const]). The explicit-specifier explicit without a constant-expression is equivalent to the explicit-specifier explicit(true). If the constant expression evaluates to true, the function is explicit. Otherwise, the function is not explicit. A ( token that follows explicit is parsed as part of the explicit-specifier.

What is the purpose of the last sentence above? Isn't this obvious from the first definition of the grammar term explicit-specifier given below?

explicit-specifier:

 explicit ( constant-expression )
 explicit 

Solution

  • The following is valid:

    struct A {
        (A)(/*...*/); //1
    };
    

    //1 declares a constructor of A with parameter list /*...*/. This is allowed because the grammar for declarators allows adding extra parentheses in various places, e.g. around the declarator-id A.

    So then there is a question of how

    struct A {
        explicit (A)(/*...*/); //2
    };
    

    should be interpreted.

    Before C++20 //2 would mean that we have the same constructor signature as in //1, but marked explicit, and the C++20 grammar without the sentence in question would still allow parsing it that way, while parsing (A) as part of the explicit-specifier wouldn't work, because () is not a valid declarator syntax and A is not an expression.

    The sentence that you are asking about forces the second interpretation making this ill-formed. The proposal doesn't make a specific argument as to why, but I suppose it is meant to avoid mistakes, since something like

    struct A {
        explicit(A) (/*...*/); //3
    };
    

    looks like explicit(A) was an explicit-specifier, although per the grammar itself, it wouldn't be parsed that way.

    This is also mentioned as breaking change in [diff.cpp17.class]/1.

    As far as I can tell, this only makes previously well-formed code ill-formed. I don't think there is any actual ambiguity without that sentence. The only code made ill-formed are declarations with extra parentheses around the declarator-id, which probably nobody uses in practice.