C++: Why a function?

Programming, for all ages and all languages.
Post Reply
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

C++: Why a function?

Post 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.
Every good solution is obvious once you've found it.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post 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(); ...
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
dave
Member
Member
Posts: 42
Joined: Sat Jul 09, 2005 11:00 pm

Post 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
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post 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? ;)
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Post 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).
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

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