Meaning of "ill-formed declaration" in L(n) - c++

A code snippet from cppreference.com is like this:
struct M { };
struct L { L(M&); };
M n;
void f() {
M(m); // declaration, equivalent to M m;
L(n); // ill-formed declaration
L(l)(m); // still a declaration
}
L(n); is commented with "ill-formed declaration".
But nearly all compilers issue message like this: no default constructor exists for class "L". That is to say, it's not considered to be ill-formed, right? Because if i throw a line L() = default; into L's body, it compiles successfully.
Is the comment wrong or misleading or compilers are not strictly standard-conforming?
Follow Up
Seems that i made something wrong with ill-formed:
ill-formed - the program has syntax errors or diagnosable semantic
errors. A conforming C++ compiler is required to issue a diagnostic, > even if it defines a language extension that assigns meaning to such > code (such as with variable-length arrays). The text of the standard > uses shall, shall not, and ill-formed to indicate these requirements.
In light of that, that line is semantically wrong.
Thanks, for you guys' answers and comments.

I think that the example demonstrates that declarator may be enclosed in parentheses.
So this declaration
M(m);
is equivalent to
M m;
that is there is declared an object m of the type M.
However this record
L(n);
can be considered as an expression statement with calling the constructor L( M & ) with the argument n of the type M or as a declaration.
The C++ Standard resolves such an ambiguity as a declaration instead of the expression statement. So in this record n is the name of the created object. But the class L does not have the default constructor. So the declaration is ill-formed because the structure L does not have the default constructor that is required for this declaration.
From the C++ 14 Standard (6.8 Ambiguity resolution)
1 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 make an expression statement instead of the declaration you can write for example
( L )( n );
This record
L(l)(m);
is a correct declaration. There is declared the object l of the type L using the constructor L( M & ).

Related

C++ Order of Declaration (in Multi-variable Declaration Line)

I use the following in my C++ code:
int a = 0, b = a;
I would like to know if this behaviour is reliable and well defined (left to right order of name declaration) and that my code will not break with other compilers with an undeclared name error.
If not reliable, I would break the statement:
int a = 0;
int b = a;
Thank you.
I believe the answer is no.
It is subject to core active issue 1342 which says:
It is not clear what, if anything, in the existing specification requires that the initialization of multiple init-declarators within a single declaration be performed in declaration order.
We have non-normative note in [dcl.decl]p3 which says:
...[ Note: A declaration with several declarators is usually
equivalent to the corresponding sequence of declarations each with a
single declarator. That is
T D1, D2, ... Dn;
is usually equivalent to
T D1; T D2; ... T Dn;
...
but it is non-normative and it does not cover the initialization case at all and as far as I can tell no normative wording says the same thing.
Although the standard does cover the scope of names in [basic.scope.pdecl]p1 which says:
The point of declaration for a name is immediately after its complete
declarator and before its initializer (if any), except as noted below.
[ Example:
unsigned char x = 12;
{ unsigned char x = x; }
Here the second x is initialized with its own (indeterminate) value.
— end example  ]
The fact that you thought to ask this question suggests that the style is not great. Even though the one-line version is almost guaranteed† to work, I would still go with the two-line approach for the greater clarity to human readers.
† I initially said it was guaranteed, but I will step back from that. After reviewing the relevant portion of the spec, I can see how language lawyers would complain that this guarantee is not explicitly stated. (As Shafik Yaghmour points out, core active issue 1342 notes the lack of an explicit guarantee, albeit with phrasing that suggests that such a guarantee should be present.)
I will step back only to "almost guaranteed", though, as it is strongly implied by "Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself.". That is, the analysis of int a = 0, b = a; has two parts: one where a variable named a is initialized to 0, and one where a variable named b is initialized to the value of a. If you are truly keeping these parts separate, then the first part would have to finish before the second part begins (otherwise they are not as if each was in a declaration by itself), so a would have the value 0 before b is initialized. I accept that this might be not definite enough for the language lawyers, but it should be good enough for a compiler's bug report if there is a compiler for which that line does not work as intended.
My apologies for not looking up the spec earlier. The "language-lawyer" tag was not present when I initially answered.
A declaration statement that defines multiple variables separated by comma is exactly equivalent to multiple declaration statements that defines a single variable in the same order because the scope of a variable begins just after it's name, but there are (at least) two exceptions:
1) When a variable declaration hides a type with the same name, as in:
struct S {};
S S, T;
Is different from
struct S {};
S S;
S T; //error: S is a variable name
But
struct S {};
S S, T{S};
Is equivalent to
struct S{};
S S;
struct S T{S};
2) When using the auto and decltype(auto) specifiers:
auto i{0}, j{i}, k{2.0}; // error: deduction for auto fails, double or int?
Is different from
auto i{0};
auto j{i};
auto k{2.0};
In any case, evaluation order is always from left to right.

Uniform Initialization inside constructor/function declaration parameter list

I am learning some basic things about classes and OOP in C++. From what I read the preferred modern way of initializing a variable is to use uniform initialization.
In the simple class header example below, uniform initialization is used to initialize the 3 data members (length, width and height).
For consistency, I thought it might be a good idea to use uniform initialization when setting default values in the constructor declaration but this does not work and the compiler (gcc 6.3 on Debian Stretch) generates and error. From what I can see the compiler thinks the curly braces {} are the start of the constructor definition body (clearly it is not since the right bracket ")" has not yet been added).
I accept this will not work but out of curiosity is there a reason why? I would prefer to be consistent with my code and use uniform initialization where ever possible.
Thanks.
#ifndef BOX_H
#define BOX_H
class Box
{
private:
double length {1.0};
double width {1.0};
double height {1.0};
public:
//constructor
Box(double l = 1.0, double w = 1.0, double h = 1.0); //ok
//Box(double l {1.0}, double w {1.0}, double h {1.0}); //Error
double volume();
};
#endif
EDIT....thanks for the comments so far but I'm not sure I understand the reason why you cannot use uniform initialization for default arguments. Is there some standard C++ documentation someone can point me to?
For example, taking the basic program below, it is ok to initialize n with a value of 5 using uniform initialization but it is not ok to initialize x like this as a default argument in the function header (I am using gcc 6.3 with -std=c++17). Why is this? Apologies if I have not understood the help so far.
#include <iostream>
void printNum(int x {1}) //error
{
std::cout<<x<<"\n";
}
int main()
{
int n {5}; //OK
printNum(n);
}
It's a grammatical constraint. This specific grammar element is described in [dcl.fct] ¶3:
parameter-declaration-clause:
parameter-declaration-listopt ...opt
parameter-declaration-list , ...
parameter-declaration-list:
parameter-declaration
parameter-declaration-list , parameter-declaration
parameter-declaration:
attribute-specifier-seqopt decl-specifier-seq declarator
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
attribute-specifier-seqopt decl-specifier-seq abstract-declaratoropt
attribute-specifier-seqopt decl-specifier-seq abstract-declaratoropt = initializer-clause
The thing to note is that the grammar permits an initializer-clause to be present only if it's preceded by a =. I suspect it's to ensure there's no ambiguity between function declarations and object declarations. For instance, in block scope:
Widget foo(CompA{}, CompB{});
Has to be an object declaration, like the uniform initialization proposal wanted to make sure. Allowing plain {} as a default argument would make the above ambiguous, and we'll just have another vexing parse to add to the collection. So a = is required.
Now, as for why not allow it in a constructor where ambiguity is unlikely: the standard committee is not really in the habit of allowing a very constrained use-case if the more general one cannot be supported.

Is "int (x), 1;" an ambiguous statement?

void f(int x) {
int (x), 1;
}
Clang compiles it, GCC doesn't. Which compiler is correct?
IMO, the wording in [stmt.ambig] is clear enough on this:
An expression-statement with a function-style explicit type conversion 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.
[Note: If the statement cannot syntactically be a declaration, there is no ambiguity, so this rule does not apply. The whole statement might need to be examined to determine whether this is the case.
The wording speaks of an entire (expression-)statement.
Your statement cannot be parsed as a declaration, because the lexeme 1 is grammatically not a declarator. There is no ambiguity: it might look ambiguous if we looked solely at int(x), but the standard quite explicitly denies that if some prefix of the statement parses as a declaration, the entire statement is considered a potential declaration.
In fact, core experts had a highly similar discussion back in 2002 over core issue 340---I highlighted the important bits. Here, again, we have a supposed declaration that contains an incompatible sub-construct.
Consider the following program:
struct Point {
Point(int){}
};
struct Lattice {
Lattice(Point, Point, int){}
};
int main(void) {
int a, b;
Lattice latt(Point(a), Point(b), 3); /* Line X */
}
The problem concerns the line marked /* Line X */, which is an ambiguous
declarations for either an object or a function. The clause that
governs this ambiguity is 8.2 [dcl.ambig.res] paragraph 1, and reads:
The ambiguity arising from the similarity between a function-style
cast and a declaration mentioned in 6.8 [stmt.ambig] [..]
Based on this clause there are two
possible interpretations of the declaration in line X:
The declaration of latt declares a function with a return value of the
type Lattice and taking three arguments. The type of the first two
arguments is Point and each of these arguments is followed by a
parameter name in redundant parentheses. The type of the third
argument can not be determined, because it is a literal. This will
result in a syntax error.
The declaration of latt declares an object,
because the other option (a function declaration) would result in a
syntax error. Note that the last sentence before the "[Note:" is not
much help, because both options are declarations.
Steve Adamczyk: a number of people replied to this posting on
comp.std.c++ saying that they did not see a problem.
The original
poster replied:
I can't do anything but agree with your argumentation. So there is
only one correct interpretation of clause 8.2 [dcl.ambig.res]
paragraph 1, but I have to say that with some rewording, the clause
can be made a lot clearer, like stating explicitly that the entire
declaration must be taken into account and that function declarations
are preferred over object declarations.
I would like to suggest the following as replacement for the current
clause 8.2 [dcl.ambig.res] paragraph 1:
The ambiguity arising from the similarity between a functionstyle cast
and a declaration mentioned in 6.8 [stmt.ambig] […]
The working group felt that the current wording is clear enough.

Can not instantiate class as LHS value with qualified enum as argument (C++ VS2015)

I'm a little bit supprised as i see this compilation error;
Here is the example:
class A
{
public:
enum eA { eA1, eA2 };
class B
{
public:
B(eA e, int i = 0);
};
A(const B &b);
};
A::A(const B &b)
{
}
A::B::B(eA e, int i /*= 0*/)
{
}
int main()
{
A::B b(A::eA1); // OK
A a0(b); // OK
A a1(A::B(A::eA1, 0)); // OK
A a2(A::B(A::eA2)); //error C2751: 'A::eA2': the name of a function parameter cannot be qualified
return 0;
}
As pointed in comments, A a2(A::B(A::eA2)); doesn't compile. Why?
I'm not asking how to compile it. Why it doesn't compile?
It compiles, if first parameter type of class-B is not from class-A. for example with int it compiles.
This is a Most Vexing Parse issue. The canonical case would be:
T t( U(x) );
where T and U are previously known to be type names. This could be parsed in two valid ways:
a declaration of t as an object of type T, with the initializer being the expression U(x), a function-style cast of the variable x to a temporary U
a declaration of t as a function returning T, with 1 parameter of type U and name x; and there are redundant parentheses around x. (Declarators may be parenthesized).
The text in the Standard for disambiguating is in [dcl.ambig.res]/1. What it says is that parsing this code hinges on whether U(x) would be a declaration or an expression, and then refers to [stmt.ambig].
In [stmt.ambig]/2 there is a clarifying example. I won't reproduce the full example here (you can look it up in a standards draft) but the accompanying text is:
If the statement cannot syntactically be a declaration, there is no ambiguity
[...] This is of course ill-formed for semantic reasons, but that does not affect the syntactic analysis. In those cases the statement is a declaration.
What this is trying to say is that if the code can be matched to the rules in the language grammar for a declaration, then it is a declaration, even if the code subsequently falls foul of a semantic rule.
Looking at your variation now, where the inner code is (simplified) U(A::e) where e is an enumerator in the scope of A.
I believe this code does still match the grammar rule for a declaration. See [dcl.decl]/4 grammar specification (selected parts):
noptr-declarator: declarator-id attribute-specifier-seqopt
declarator-id: ...opt id-expression
and id-expression can be qualified-id or unqualified-id, and finally, A::e is a qualified-id.
Even though there is a semantic rule [dcl.meaning]/1 that the declarator-id can only be a qualified-id in certain contexts, excluding this case, that's not a grammar rule.
So I would say VC is correct to reject the code.
To fix the code, assuming the intent is for a2 to be an object declaration, you can use the same techniques as mentioned on the canonical MVP thread:
A a2{A::B(A::eA2)}; // braced initialization
A a2((A::B(A::eA2))); // function declarations can't have extra parentheses around the entire parameter declaration, so this cannot be a function declaration

Variable with same name as type - which compiler is right?

In this code:
typedef int foo;
struct S
{
foo foo;
};
int main() {}
all versions of clang -std=c++14 accept this code, however all versions of g++ -std=c++14 report:
5 : error: declaration of 'foo S::foo' [-fpermissive]
foo foo;
^
1 : error: changes meaning of 'foo' from 'typedef int foo' [-fpermissive]
Is the code correct?
The code is wrong. typedef is a new name for a existing type. So you can not create a variable with a type's name like foo foo; is equal to int int.
g++ -std=c++14 is the correct one.
Also refer this question
According to the C++ standard, declaring a variable with the same name as a type is correct code in general, but invalid code within a class definition. The class case is specific, because names declared in a class definition are visible within the whole class definition, before and after the point of declaration of that name. In other scopes (global, namespace, function, ...) declared names are visible only after the point of declaration.
For the example given in the question: If you have another reference to foo before the member declaration foo foo;,
struct S { foo another_member; foo foo; };
to which foo should it refer? To the type or the member foo? In this case it would be possible to deduce from the context that the type is meant, but the C++ standard probably avoided complexity for treating corner cases.
But foo foo; is valid code outside of class definitions: Additionally to the excerpt from section [dcl.spec], which Serge Ballesta already citied in his answer, section [dcl.decl] is useful in this context. It gives a valid example for this case (in older versions of the C++ standard text in a note below the text, in later versions as part of the main text) - here from the N3242 draft (final draft for C++11):
A declaration with several declarators is usually equivalent to the corresponding sequence of declarations each with a single declarator. That is
T D1, D2, ... Dn;
is usually equvalent to
T D1; T D2; ... T Dn;
where T is a decl-specifier-seq and each Di is an init-declarator.
The exception occurs when a name introduced by one of the declarators
hides a type name used by the decl-specifiers, so that when the same
decl-specifiers are used in a subsequent declaration, they do not have
the same meaning, as in
struct S ... ;
S S, T; // declare two instances of struct S
which is not equivalent to
struct S ... ;
S S;
S T; // error
The excerpt from section [dcl.spec] is useful as well, as it describes, when a name in a declaration of a variable is interpreted as type name and when as the variable name (long quote is given in Serge Ballesta's answer):
... it is interpreted as part of the decl-specifier-seq if and only if
...
The relevant section for the class' case, which is given in the original question, is [basic.scope.class]:
... A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in
the completed scope of S. No diagnostic is required for a violation of this rule. ...
This means that the code of the original question is invalid, but the compiler does not need to give an error. So both clang and gcc behave correctly (according to the C++ standard).
I would say CLang is correct here - even if I would never use this.
C++ 14 draft N4296 says in 7.1 Specifiers [dcl.spec] 3
If a type-name is encountered while parsing a decl-specifier-seq, it is interpreted as part of the decl-specifier-
seq if and only if there is no previous type-specifier other than a cv-qualifier in the decl-specifier-seq. The
sequence shall be self-consistent as described below. [ Example:
typedef char* Pc;
static Pc; // error: name missing
Here, the declaration static Pc is ill-formed because no name was specified for the static variable of type Pc.
To get a variable called Pc, a type-specifier (other than const or volatile) has to be present to indicate that
the typedef-name Pc is the name being (re)declared, rather than being part of the decl-specifier sequence.
For another example,
void f(const Pc); // void f(char* const) (not const char*)
void g(const int Pc); // void g(const int)
(emphasize mine)
Even if an example is not normative, it let think that for the writers of C++ specification, a variable can redeclare the name of a typedef.
But g++ is simply more conservative what looks more reasonable. If I ever see such a construct in production code, the programmer would soon learn not to do it again, even I the compiler accepted it...