TITLE: Type-ids, temporaries, and static variable constructors RESPONSE: jamshid@ses.com (Jamshid Afshar), 15 Jun 94 [...] I nominate the following construct as the simplest piece of code that break the most number of modern compilers. void f() { static A a(A()); } Not only is that the simplest piece of code that breaks the most number of modern C++ compilers, but it also breaks the most number of comp.lang.c++ regulars ;-). As Anthony Scian (ANTHONY@watcom.on.ca) and John Spicer (jhs@edg.com) pointed out in email, and John Tam (johntam@vnet.ibm.com) posted in a followup, the above code is NOT correct C++. Watcom C++, IBM C++ and the latest EDG compiler correctly give an error about the above code because the declaration: static A a(A()); must be interpreted as a function declaration named `a' returning an A and taking one `A(*)()' parameter. You can't declare static functions inside another function. Cfront, g++, Symantec, and BC++ fail to diagnose the error. I don't know about Microsoft C++ or DEC C++. If you're wondering how "A()" can be interpreted as a function pointer type, remember that function pointer types are treated similarily to array types when used as parameters. void f( int g() ); is treated exactly like the more commonly used: void f( int (*g)() ); This is somewhat analogous to the declaration of the array parameter: void h( int a[10] ); being treated exactly like: void h( int* a ); Anyway, WP 8.2 says "the resolution is that any construct that could possibly be a type-id in its syntactic context shall be considered a type-id". A type-id is "syntactically a declaration of an object or function of that type that omits the name of the object or function. For example: int // int i int * // int *pi int (*)[3] // int (*p3i)[3] WP 8.2 also says that a declaration can be explicitly disambiguated between a type declaration with a redundant set of parenthesis and an object declaration by using nonfunction-style casts or an = to indicate initialization: struct S { S(int); }; void f( double a ) { S x( int(a) ); // function declaration S y( (int)a ); // object declaration S z = int(a); // object declaration } Applying this to the original example, we have to write: void f() { static A a = A(); cout << "f() called" << endl; } But please note the intended bug report from the original post is still valid. Many modern compilers incorrectly handle the destruction of temporaries used to initialize a static variable. Imagine A had a constructor taking a Tmp object: void f() { static A a( Tmp(1) ); } BC++ 4.0, Cfront 3.0.2, Symantec C++ 6 and Watcom C++ v10 do not correctly handle this code. These compilers either forget to destroy the temporary or they try to destroy the temporary every time the function is called even though the temporary is only constructed once. Btw, Anthony from Watcom told me this bug in v10 is a slip up because v9.5 does correctly handle it. I believe IBM C++ and the latest EDG also get this right. Anyone know about DEC C++, MS C++, or Symantec C++ v7? A test program is appended. [...] /* test program; should output: Tmp constructor called A(Tmp) constructor called Tmp destructor called f() called f() called f() called f() called f() called A destructor called */ #include struct Tmp { Tmp(int) { cout << "Tmp constructor called" << endl; } ~Tmp() { cout << "Tmp destructor called" << endl; } }; struct A { A() { cout << "A constructor called" << endl; } A( const A& ) { cout << "A copy constructor called" << endl; } A(Tmp) { cout << "A(Tmp) constructor called" << endl; } ~A() { cout << "A destructor called" << endl; } }; void f() { static A a(Tmp(1)); cout << "f() called" << endl; } int main() { f(); f(); f(); f(); f(); return 0; }