I came upon a similar piece of code during an IRC discussion. While I am certain that some may consider this example trivial, I admit that the correct answer eluded me even after I verified the result with the compiler – it wasn’t until I checked the standard that it became clear.

Consider the following class:

struct foo { foo ( ) { cout << __PRETTY_FUNCTION__ << endl ; } foo ( int ) { cout << __PRETTY_FUNCTION__ << endl ; } } ; struct foo { foo() { cout << __PRETTY_FUNCTION__ << endl; } foo(int) { cout << __PRETTY_FUNCTION__ << endl; } };

And now, consider the following code:

int global ; int main ( ) { foo ( ) ; foo ( 42 ) ; foo ( global ) ; } int global; int main() { foo(); foo(42); foo(global); }

Would you care to guess what will be printed?

Spacer to avoid “spoilers” Spacer to avoid “spoilers”

Well, the answer is:

foo::foo() foo::foo(int) foo::foo() foo::foo() foo::foo(int) foo::foo()

[link]

The line foo(global); doesn’t cause the foo::foo(int) constructor to run, instead causing the default one to be executed. Why is that?

The answer is fairly simple, if vexing, as was spoilt in the title: the C syntax rules, that C++ was saddled with, declare that

N4140 § 6.8 [stmt.ambig] / 1

An expression-statement with a function-style explicit type conversion ([expr.type.conv]) 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.

It then follows with an example that depicts a nearly identical problem:

N4140 § 6.8 [stmt.ambig] / 2 class T { // ... public : T ( ) ; T ( int ) ; T ( int , int ) ; } ; T ( a ) ; // declaration class T { // ... public: T(); T(int); T(int, int); }; T(a); // declaration

This is exactly the same principle that allows the Most Vexing Parse to exist, and that drove the standards committee to design mostly uniform initialiation added in C++11 (and made even less uniform in C++17).

In this case, it meant that foo(global); declared a new local variable called global, shadowing the global global variable. The parentheses here were entirely optional and the meaning of this declaration was identical to foo global;.

int global ; int main ( ) { foo ( ) ; foo ( 42 ) ; foo global ; // the same thing! } int global; int main() { foo(); foo(42); foo global; // the same thing! }

That is also the reason why the default constructor was executed.

All in all, this whole situation could be avoided with the uniform initialization: