Page 1 of 1

C++: Why a function?

Posted: Thu Jan 11, 2007 9:42 am
by Solar
I just had a strange problem. I found a workaround, but I'm not at all sure why the compiler hickupped here (code anonymized and condensed as this is from company work, please don't complain about style or meaningfullness):

Code: Select all

namespace {
   template <typename T> struct Foo {
      Foo( T const& val ) : mVal( val ) {}
      void test() {}
      T mVal;
   };
} // namespace

void MyNamespace::callTest() {
      Foo<double> f1( 42.0 ).test();
}
The output indicates that somehow the compiler sees something else in the last code line than I do:

Code: Select all

Error: Unexpected type name "::Foo<double>" encountered.
Error: The function "f1" must have a prototype.
Error: Badly formed expression.
It turned out that this works alright:

Code: Select all

void MyNamespace::callTest() {
   Foo<double> f1( 42.0 );
   f1.test();
}
Does someone understand the depths of C++ parsing well enough to tell me what exactly went wrong in the first version of callTest()?

For the curious, the compiler is Sun C++ 5.8 Patch 121017-01.

Posted: Thu Jan 11, 2007 10:20 am
by Combuster
Though i'm definately no expert, i get the idea that it evaluates f1( 42.0 ).test() before Foo<double>

i.e. it tries to compute the first part, then it sees Foo value (instead of Foo name), complains, continues, sees that f1 is missing, before bailing out. Why it behaves that way is beyond me as it makes no sense, although this is the closest fit to the error messages i can think of.

Maybe it does eat ( Foo<double> f1( 42.0 ) ).test(); ...

Posted: Thu Jan 11, 2007 11:12 am
by dave
Well, it appears as if you are trying to create the struct Foo and use a member function at the same time. It is not possible, afaik, to do both of those things in a single statment in C/C++. You must first create the instance of your object ( class, struct, etc...) and then call your member functions.

The error, The function "f1" must have a prototype, is due to the fact you confused the compiler with syntax and it is trying to figure out what you mean.

In other words, what your calling a workaround is actually the correct usage. The first method was incorrect.

Dave

Posted: Thu Jan 11, 2007 12:38 pm
by Candy
I think the compiler sees a construct <name> '(' .* ')' and expects it to be determined as a function definition, call or a variable depending on the following characters. The first would be illegal (but is parsed with the same code as a variable definition so it is a case that you have to consider), the second would be in an assignment or such and would for example be followed by a dot, while the third would always be followed by a comma or a semicolon. Due to the dot it tries to parse the f1(...) as a function call acting on its return value, which isn't matched by either a function definition or a variable definition. It can't match the resulting function (since f1 isn't defined, first error), it recognises ::Foo<...> in front of a function call which it can't match and then figures you screwed up very badly since the undefined function f1 (probably defaulting to int by C convention) doesn't have a function test() defined on it.

Didn't you have to parse this stuff in astyle?

Oh, and what are you trying to do that made you type this illegible abomination? Trying to secure a fixed contract? ;)

Posted: Thu Jan 11, 2007 1:40 pm
by Colonel Kernel
I wonder if it would have worked if you had omitted the variable name:

Code: Select all

void MyNamespace::callTest() {
   Foo<double>( 42.0 ).test();
}
It seems to me that in some cases it is possible to call a method on an instance-creation expression in the same statement... Maybe this is it?

The second error message sounds related to "C++'s Most Vexing Parse" (see Item 6 of "Effective STL" by Scott Meyers).

Posted: Thu Jan 11, 2007 3:41 pm
by Candy
Colonel Kernel wrote:I wonder if it would have worked if you had omitted the variable name:

Code: Select all

void MyNamespace::callTest() {
   Foo<double>( 42.0 ).test();
}
It seems to me that in some cases it is possible to call a method on an instance-creation expression in the same statement... Maybe this is it?

The second error message sounds related to "C++'s Most Vexing Parse" (see Item 6 of "Effective STL" by Scott Meyers).
This would be either an invocation on a temporary object or a static function invocation on a template object type:

Code: Select all

(Foo<double>(42.0)).test();
or

Code: Select all

Foo<double>::test();
The first looks quite like what Solar did except that it did have a variable name. Lemme just test this :)

Ok, just tested both, they compile (and I expect they'll work too).