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

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.

Related

I do not understand why this compiles

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

Infinite loop in constructor without for or while

I did a test here, but the output is a loop without ending, I don't know why.
Actually, I am doing another test, but when I wrote this, I don't understand how the loop occurred. It is output "ABC" repeatedly.
#include <map>
#include <string>
#include <iostream>
class test
{
public:
std::map <int, int> _b;
test();
test (std::map<int, int> & im);
~test();
};
test::test()
{
std::cout<<"abc";
_b.clear();
_b[1]=1;
test(_b);
}
test::test(std::map <int, int>& im)
{
std::cout<<im[1];
}
test::~test() {};
int main ()
{
test a;
}
The issue here is that the compiler interprets the statement
test(_b);
not as code that creates a temporary object of type test passing in parameter _b, but as a variable declaration for a variable named _b of type test, using the default constructor. Consequently, what looks like a piece of code that creates a temporary test object using the second constructor is instead recursively creating a new object of type test and invoking the constructor another time.
To fix this, you can give the variable an explicit name, such as
test t(_b);
This can only be interpreted as a variable of type test named t, initialized using the second constructor.
I have never seen this before, and I've been programming in C++ for years. Thanks for showing me yet another corner case of the language!
For an official explanation: According to the C++03 ISO spec, §6.8:
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.
(My emphasis). In other words, any time C++ could interpret a statement as either an expression (the temporary object cast) or as a declaration (of a variable), it will pick the declaration. The C++ spec explicitly gives
T(a);
As an example of a declaration, not a cast of a to something of type T.
This is C++'s Most Vexing Parse - what looks like an expression is instead getting interpreted as a declaration. I've seen the MVP before, but I have never seen it in this context.
the problem is from constructor you again calling the contructor test(_b)
test::test(){std::cout<<"abc";_b.clear();_b[1]=1;test(_b);}
here is what happens
everytime you call test(_b) it first calls default constructor test::test and it in turns calls the test(_b) and the loop goes on and on untill the stack overflows.
remove the test(_b) from the default constructor
I'm pretty sure that you are not actually "calling the constructor" since they are not directly callable IIRC. The legalese had to do with constructors not being named functions - I don't have a copy of the Standard handy or I might quote it. I believe what you are doing with test(_b) is creating an unnamed a temporary which invokes the default constructor again.
I'm not familiar with the particularities of the standard, but it may be that calling a constructor within a constructor is undefined. As such it could be compiler dependent. In this particular case it causes infinite recursion of your default constructor without ever calling your constructor with the map argument.
C++ FAQ 10.3 has an example with a constructor that has two parameters. If you add an int parameters to your second constructor such as test(map, int), it exhibits a somewhat normal behaviour.
For good form I would simply change test::test(std::map <int, int>& im) for test::testInit(std::map <int, int>& im), and test(_b) to testInit(_b).

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

Error C2228 when constructing boost::function object in constructor argument list

The code below does not compile in Visual C++ 2005.
class SomeClass {
public: boost::function<void()> func;
SomeClass(boost::function<void()> &func): func(func) { }
};
void someFunc() {
std::cout << "someFunc" << std::endl;
}
int main() {
SomeClass sc(boost::function<void()>(&someFunc));
sc.func(); // error C2228: left of '.func' must have class/struct/union
return 0;
}
If I put parentheses around the argument to the SomeClass constructor or constructs the boost::function object outside the argument list it compiles fine.
SomeClass sc((boost::function<void()>(&someFunc)));
// or
boost::function<void()> f(&someFunc);
SomeClass sc(f);
What is the problem with the previous code?
It's a function declaration for a function taking a reference to a boost:function <void()> and returning a SomeClass. You can memorize the following rule, which turns out to apply to many other such disambiguation cases. You can find descriptions of these cases in section 8.2 of the C++ Standard.
Any construct that could possibly be a declaration will be taken as a declaration
That means, the following will be taken as a parameter declaration, with superfluous parentheses
boost::function<void()>(&someFunc)
If you remove the parentheses, this will become clear
boost::function<void()> &someFunc
And thus, the whole declaration will not anymore declare an object, but a function
SomeClass sc(boost::function<void()> &someFunc);
To fix it, use the cast-notation
SomeClass sc((boost::function<void()>)&someFunc);
Or put parentheses around the whole expression, like you did.
Here is the Standard in all its glory from 8.2:
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 construct that could possibly be a declaration a declaration. [Note: a declaration can be explicitly disambiguated by a nonfunction-style cast, by a = to indicate initialization or by removing the redundant parentheses around the parameter name. ]
Note that for controlling precedence, you are allowed to introduce parentheses just about anywhere, like in the following
int (((((((a))))))) = 3;
int (*(pa)) = &a;
This is known as "C++'s Most Vexing Parse" (from a book by Scott Meyers called Effective STL).
As answered above, the compiler prefers to interpret the problematic line as a function declaration.

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.