TITLE: Ambiguity in declaration vs expression? PROBLEM: jamshid@ses.com, 2 Mar 95 Shiping encountered some code like the following that was giving a compiler error on the IBM AIX compiler (xlC). class TQueryData { //... public: TQueryData (); class SQueryList { // a nested class //... public: SQueryList() {} }; void setListValue( int , const TQueryData& ); TQueryData (const SQueryList&); }; void mkToken (const TQueryData& type) { TQueryData token (TQueryData::SQueryList()); token.setListValue(0, type); // error: left side must be an object } Apparently the compiler didn't think "token" was declared or initialized correctly. It turns out that xlC interprets the declaration of "token" as a function instead of a local variable definition! It's as if the code was: void mkToken (const TQueryData& type) { TQueryData token ( TQueryData::SQueryList (*) () ); token.setListValue(0, type); // error: left side must be an object } Ugh, an IBM compiler bug, right? NO, xlC is correct! Our code (and Cfront, which we use on the Sun and HP) is incorrect. In fact, I think all but one problem Shiping has encountered porting the C++ Wb 3.0 branch to xlC have been due to bugs in our code. Hopefully he can move all these changes onto the trunk too so that we don't have to re-fix our code the next time we port to another (correct) compiler. Our guidelines should probably be updated to include problems found when porting to xlC. I hope to see more cross-compiler concurrent development to nip code bugs like these before they spread. Why xlC is interpreting the code like this is not obvious. In C and C++ you can declare function parameters without naming them and without using the "(*)" syntax. The following declarations of f() are all equivalent. void f( int (*callback)() ); // legal, good style void f( int (*)() ); // legal, bad style (no parameter name) void f( int (callback)() ); // legal, bad style (function==func. ptr) void f( int callback() ); // legal, bad style (parens redundant) void f( int () ); // legal, bad style (no parameter name) This should help you see why the above definition of "token" was interpreted as a function prototype. The ARM (6.8 Ambiguity Resolution) rule is that "TQueryData::SQueryList()" is interpreted as a declaration (ie, the function parameter type "TQueryData::SQueryList (*)()") if at all possible instead of being interpreted as an expression (ie, construct a temporary SQueryList object). There's only a couple of workarounds I can think of: 1. Use the "=" for of initialization instead of parenthesis. This requires that the copy constructor be defined (many of our classes do not implement them). Note: the "=" below does NOT have anything to do with the assignmnt operator function. The "T a=b;" style of initialization is often deprecated for efficiency reasons (technically it requires a temporary objects to be created), but good compilers will optimize it to be the same as the "T a(b);". void mkToken (const TQueryData& type) { TQueryData token = TQueryData::SQueryList(); 2. Use an explicit temporary. This is kinda ugly and verbose. Alternative: declare and use a global "const TQueryData::SQueryList gEmptyQueryList;". void mkToken (const TQueryData& type) { TQueryData::SQueryList tmp; TQueryData token(tmp);