I do not understand why this compiles - c++

I'm certainly missing something, but I do not understand why this compiles (with both g++ & clang++):
struct A
{
};
struct B
{
};
int main()
{
A a(B);
}
First of all, B is a type... not a value. How should I interpret this code?

It's interpreted as the declaration of a function named a, which takes one argument of type B and returns A.

It's simply a function declaration declaring a to be a function returning A and taking one unnamed parameter of type B.
It is valid because function declarations as opposed to function definitions are allowed within function definitions.

This issue is known as the most vexing parse. The line A a(B); can be interpreted as the declaration of a function named a returning an object of type A and taking an unnamed parameter of type B.
One way to avoid this issue is to use the uniform initialization syntax which was introduced in C++11, which consists in using braces instead of parenthesis: A a{B}; returns an error. The line is now interpreted as a variable declaration initialized with B, which is a type instead of a value.
Here's more information:
The Most Vexing Parse: How to Spot It and Fix It Quickly

Related

Why CLS() has different meanings in C++11

VS2010 has supported the C++11 partially. I compile the code below in VS2010 RTM. I'm confused why the code CLS() is analyzed to different meanings. In the line "decltype(CLS()) obj1;", the CLS() denotes an class object entity. But in the line "CLS obj2(CLS());", the CLS() denotes a function pointer, which retuns a CLS object with no parameter. Is the behavior expected? Is it described in the standard?
struct CLS
{
int mi;
};
int _tmain(int argc, _TCHAR* argv[])
{
decltype(CLS()) obj1;
obj1.mi = 10;
CLS obj2(CLS());
obj2.mi = 10; // error C2228: left of '.mi' must have class/struct/union
return 0;
}
UPDATE 12/8/2011
Per C++11 7.1.6.2/1, the expected string in the parenthesis is an expression. The compiler just needs to check if the string can be parsed as a valid expression. If yes, the code is well-formed. So for the code “decltype(CLS()) obj1;”, the "CLS()" is treated as a valid expression which denotes a difinition of object.
decltype-specifier:
decltype ( expression )
UPDATE 1/3/2012
Potatoswatter gives the explanation why "CLS obj2(CLS());" is a declaration other than an object definition.
Anything that may be interpreted as either an expression or a declaration is a declaration, however unusual it may be. CLS obj2( CLS() ); declares a function whose parameter type CLS() is a function with no arguments returning CLS, and whose return type is CLS.
Is it expected: Yes
It is known as the "most vexing parse".
CLS obj2(CLS()); // function forward declaration.
CLS obj2 = CLS(); // Creates object zero initialized.
CLS obj2; // Creates object default initialized.
As others have said, this is the Most Vexing Parse. Anything that may be interpreted as either an expression or a declaration is a declaration, however unusual it may be. CLS obj2( CLS() ); declares a function whose parameter type CLS() is a function with no arguments returning CLS, and whose return type is CLS.
For example,
CLS obj2( CLS() ); // forward declaration
CLS obj2( CLS fun() ) { // definition
return fun(); // use unusual functional argument
}
CLS foo() { // define a function to use as unusual argument
return CLS();
}
int main() {
CLS obj2( CLS() ); // still a forward declaration, even in this context!
CLS x = obj2( foo );
}
The solution is to use C++11's uniform initialization:
CLS obj2{ CLS() };
or simply
CLS obj2{};
In the argument of decltype, an expression is expected. The only way of interpreting CLS() as an expression is to parse it as default constructed object of type CLS.
However, in CLS obj2(CLS()) (which BTW works the same way in C++03) there are two possible parses: One as function declaration and one as object definition. As function declaration, the outer parentheses form a parameter list, and the content is expected to specify a parameter (or a list of them) by giving types and optional names. In that parse, CLS() is interpreted as function type.
The other valid parse is as definition of an object. For that parse, of course in the parentheses there has to be an expression (or a list of them), giving the interpretation of CLS() as default-constructed object of type CLS.
Now in C++ there is a rule that if something can be parsed both as a declaration and as a definition, it will be parsed as a declaration. That is, in this case the first interpretation will be used.
This of course gives rise to the question of why the first interpretation is chosen when we would clearly expect the second one here. And the answer is that otherwise it would break C compatibility (and in some cases even our expectations). For example, look at the following line:
int f();
Now you would agree that this declares a function taking no arguments and returning int, right? But it could also be parsed as definition of a default-initialized variable of type int. Thanks to the rule mentioned above, it indeed declares a function returning int.
A rule which gives always the result which one would expect would in the best case be complex, but most probably impossible.
Note that in C++03, an easy way to avoid it for automatic variables would have been to prefix the definition with auto: Since function declarations never start with auto, this would have forced the compiler to interpret it as variable definition. Since the old meaning of auto was removed in C++11, this no longer works (and for non-automatic variables it never worked anyway).

Why is the compiler not warning about definitions with no names?

The following C++ code does nothing (using GCC 4.4.3) - it does not print the text:
struct MyStruct { MyStruct() { cout << "Hello" << endl; } };
void foo() {
MyStruct ();
}
I think this is not so obvious... Let alone the danger of forgetting to give a variable name. Is there a compiler option/warning to forbid compilation of such code or is there any hidden secret behind allowing it?
Edit: I am sorry. The version above MyStruct(); acutally prints. The version which is not printing is:
void bar() {
MyStruct a();
}
So now I am a bit confused.
This is not a declaration, because in MyStruct ();, the MyStruct would be part of the decl-specifier-seq and forms a type-name therein. And then () can only be a function-declarator. This requires that there is a declarator-id specified, which in your case is not. A special syntactical form is needed to allow such a syntax in declaring a constructor. But such syntactical exceptions are not made in a declaration-statement.
So this construct cannot be a declaration. It is parsed as an expression which specifies a functional cast creating a temporary of type MyStruct.
If the compiler does not print Hello it is either non-conforming or you are not calling foo in your program.
Your edit also does not specify a declaration without a name. It instead specifies a declaration that does have a name. It declares a function that is called a. The compiler has no way that you meant something else by this.
MyStruct a();
It could in an effort deduce this by having a recovering rule when it later discovers errors in your code such as the following
a.f();
If you have this in your code to try and call a member function and "a" is a function, the compiler could check to see if MyStruct contains a member f such that this expression is well-formed. But what if you just forgot to place parentheses? The following would be valid for the above declared function that returns a MyStruct, assuming a suitably declared member f.
a().f();
So in effect, the compiler can't really know what you mean.
You don't have "a declaration with no name" in your code. You have a completely valid expression MyStruct(). It is not a declaration, once again, it is an expression statement. If it doesn't print anything, it mist be the effect of optimization: in C++ it is generally allowed to eliminate temporaries, even if their constructors/destructors have side effects. (Although this context is not really one where such elimination is allowed. Are you sure you actually execute that expression statement?)
MyStruct a(); declares a function a that takes no arguments and returns a MyStruct.
I think the temporary is elided [due to compiler optimization], hence you don't see the call to the c-tor.
Your code is syntactically perfect so there is no need for the compiler to give a warning [as such].
EDIT [As per the edits in the OP]
MyStruct a();
The above is parsed as the declaration of a function a return a MyStruct object and taking no parameters.
Well, temporary objects are perfectly legals. So there is no reasons to warn here.

trick question regarding declaration syntax in C++

Have a look here:
In the following code, what would be the type of b?
struct A {
A (int i) {}
};
struct B {
B (A a) {}
};
int main () {
int i = 1;
B b(A(i)); // what would be the type of b
return 0;
}
I'll appreciate it if anybody could explain to me thoroughly why would such syntax exist :)
Thanks.
One of C's warts (and C++ inherits it (and makes it worse)) is that there is no special syntax for introducing a declaration. This means declarations often look like executable code. Another example:
A * a;
Is this multiplying A by a, or is it declaring something? In order to make sense of this line you have to know that A is the name of a type.
The basic rule in C++ is that if something can be parsed as a declaration, it is. In this instance it leads to a strange and surprising result. Function declarations look a lot like function calls, and in particular the ( after the A can be thought of in a couple of ways.
You can get around this in this example with extra parenthesis that remove the compiler's ability to parse the code as a declaration.
B b((A(i)));
In C this isn't ambiguous because there is no function style of constructor call because there are no constructors. A is either the name of a type, or it's the name of a function. It can't be both.
It is a local function declaration according to C++ Standard 8.2/1. You could use implicit form of constructor to avoid this or the following:
B b(A(i)); // is equal to B b( A i );
// ---
// to declare variable of type B write:
B b = A(i);
// explicit form if you want:
B b( static_cast<A>(A(i)) );
// or
B b( (A)i );
C++ Standard 8.2/1:
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8
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 6.8, the resolution is to consider any con-
struct that could possibly be a declaration a declaration.
B b(A(i));
is equivalent to
B b(A i);
- the parenthesis around the argument name are optional -, which is equivalent to
B b(A);
- the parameter name is optional in function declarations. Hence it is a function declaration.
Typically you run into it with
X x();
- not default constructor as expected -, but there are more complicated cases when using temporaries all the way, e.g
vector<int> v(istream_iterator<int>(cin), istream_iterator<int>());

C++ enum not properly recognized by compiler

Can anyone explain why the following code does not compile (on g++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-49))?
struct X {
public:
enum State { A, B, C };
X(State s) {}
};
int main()
{
X(X::A);
}
The message I get is:
jjj.cpp: In function 'int main()':
jjj.cpp:10: 'X X::A' is not a static member of 'struct X'
jjj.cpp:10: no matching function for call to 'X::X()'
jjj.cpp:1: candidates are: X::X(const X&)
jjj.cpp:5: X::X(X::State)`
Is this bad code or a compiler bug?
Problem solved by Neil+Konrad. See the comments to Neil's answer below.
You've forgot the variable name in your definition:
int main()
{
X my_x(X::A);
}
Your code confuses the compiler because syntactically it can't distinguish this from a function declaration (returning X and passing X::A as an argument). When in doubt, the C++ compiler always disambiguates in favour of a declaration.
The solution is to introduce redundant parentheses around the X since the compiler forbids parentheses around types (as opposed to constructo calls etc.):
(X(X::A));
X(X::A);
is being seen a s a function declaration. If you really want this code, use:
(X)(X::A);
Just to make it crystal clear what happens. Look at this example
int main() {
float a = 0;
{
int(a); // no-op?
a = 1;
}
cout << a;
}
What will it output? Well, it will output 0. The int(a) of above can be parsed in two different ways:
Cast to int and discard the result
Declare a variable called a. But ignore the parentheses around the identifier.
The compiler, when such a situation appears where a function-style cast is used in a statement and it looks like a declaration too, will always take it as a declaration. When it can't syntactically be a declaration (the compiler will look at the whole line to determine that), it will be taken to be an expression. Thus we are assigning to the inner a above, leaving the outer a at zero.
Now, your case is exactly that. You are trying (accidentally) to declare an identifier called A within a class called X:
X (X::A); // parsed as X X::A;
The compiler then goes on to moan about a not declared default constructor, because the static, as it assumes it to be, is default constructed. But even if you had a default constructor for X, it of course is still wrong because neither A is a static member of X, nor a static of X can be defined/declared at block scope.
You can make it not look like a declaration by doing several things. First, you can paren the whole expression, which makes it not look like a declaration anymore. Or just paren the type that is cast to. Both of these disambiguations have been mentioned in other answers:
(X(X::A)); (X)(X::A)
There is a similar, but distinct ambiguity when you try to actually declare an object. Look at this example:
int main() {
float a = 0;
int b(int(a)); // object or function?
}
Because int(a) can be both the declaration of a parameter called a and the explicit conversion (cast) of the float-variable to an int, the compiler decides again that that is a declaration. Thus, we happen to declare a function called b, which takes an integer argument and returns an integer. There are several possibilities how to disambiguate that, based on the disambiguation of above:
int b((int(a))); int b((int)a);
You should declare an object as
X x(X::A);
Bug in your code.
Either of these two lines work for me:
X obj(X::A);
X obj2 = X(X::A);
As Neil Butterworth points out, X(X::A) is being treated as a function declaration. If you really want an anonymous object, (X)(X::A) will construct an X object and immediately delete it.
You could, of course, just do something like this:
int main()
{
// code
{
X temp(X::A);
}
// more code
}
This would be more readable and basically have the same effect.

Why isn't it possible to have an anonymous object as argument in a function argument list? C++

For example:
struct test
{};
void thing(test())
{}
int main()
{
thing(test());
}
This code would give me error; however, the next example won't give me error:
void thing(int())
{}
int main()
{
thing(int());
}
My main question is, why the first example isn't possible and the second one is? Ultimately, both test and int are types, so I can't think why declaring an anonymous object of test in the thing function argument list isn't possible whereas declaring an anonymous object of type int in the thing function argument list is.
It is possible; it's just that you're doing it wrong.
Here is a declaration of a function taking an unnamed parameter of type test:
void thing(test);
Here is a declaration of a function taking an unnamed parameter of type pointer-to-function-returning-test:
void thing(test());
You want the former, not the latter.
That your second code example works is actually a magical oddity, stemming from the fact that int() is 0 is a valid null pointer constant, which may be used to initialise a function pointer; the example breaks as soon as you swap int() for some other integer, or if you run the code in a completely compliant C++14 compiler (because C++14 made it so that 0 but not int() is a valid null pointer constant).