Brainfart: GCC and templates (10)

1 Name: #!/usr/bin/anonymous : 2006-10-25 16:04 ID:yRl1iPbl

Trying to get back into C++ after only using python for almost a year. I ran into this one while trying out partial template specialization, narrowed it down to this simple test case...

#include <iostream>
using namespace std;
template <class T>
struct wtf {
T member;
wtf():member() {}
void message() {
cout << "this is wtf " << member << " ." << endl;
}
};
template <class T>
struct wtf2 : public wtf<T> {
void message() {
/* 1 */ cout << "this is wtf2 " << member << " " << endl;
// /* 2 */ cout << "this is wtf2 " << wtf<T>::member << " " << endl;
// /* 3 */ cout << "this is wtf2 " << this->member << " " << endl;
}
};
int main() {
wtf2<int> test;
test.message();
return 0;
}

The line marked with 1 makes my gcc throw a "member undeclared" (gcc 3.4.x) or "member: not declared in this score" error (gcc 4.0.x). Versions 2 and 3 compile fine. MSVC 2003 compiles all three versions. Removing the template from the wtf2 class and inheriting from a concrete base (for example wtf<int>) makes it work in gcc, too.

Now I'm pretty sure I'm doing something wrong here (I trust g++ to know the standard more than myself), but why is it that it barfs on something that looks this trivial? Is there some dumb name lookup / scope thing that I'm missing? :(

2 Name: #!/usr/bin/anonymous : 2006-10-25 21:01 ID:WQDDjra2

structs can have functions?

3 Name: #!/usr/bin/anonymous : 2006-10-25 21:55 ID:cRCqb5aI

>>2
Yes. In C++, the only difference between a struct and a function is that a struct's members are public by default, if I recall right.

4 Name: #!/usr/bin/anonymous : 2006-10-26 07:45 ID:GufioEP4

...ugh, should've googled more first. Apparently it's two-phase name lookup that makes it barf.

Templates and accessing inherited members
http://groups.google.com/group/comp.lang.c++/browse_thread/thread/7b1863222072b340/b75b5b2de84a0a1a

5 Name: #!/usr/bin/anonymous : 2006-10-29 08:39 ID:cMRxjRN8

Isn't partial specialization the sort of thing that you should only whip out if your execution time and/or cache profilers tell you that yeah, maybe using a 32-bit integer for a boolean value wasn't that smart after all?

6 Name: #!/usr/bin/anonymous : 2006-10-29 08:55 ID:cMRxjRN8

>>3
Plus, structs have different alignment rules. I seem to recall that classes' members may be even reordered to get better packing in the presence of alignment constraints, whereas structs need to appear in memory as they are declared.

Where the vtable pointer appears in the struct, I have no idea. It would sound like a rather bad idea to rely on the in-memory format of a structure that has virtual methods.

7 Name: #!/usr/bin/anonymous : 2006-11-10 00:40 ID:6aGbySab

>>6

>>Plus, structs have different alignment rules. I seem to recall that classes' members may be even reordered

blinks

looks at his Vector3D class

looks at use of Vector3D for position (pos) member in a skeletal Joint class

sweats

looks at Joint::draw() function that has the line:

glVertex3fv ((float*)&jointarray[i].pos);

sweats

sweats sweats sweats sweats sweats sweats sweats sweats

Uh oh.

I just hope you're wrong. Right now nothing seems to get jumbled or switcharooed. I picked up that "trick" (if you can call it that... it's elementary pointer arithmetic) from studying source code in professionally-made open-source games and renderers (Quake 3, Blender, etc) made by people who know more about C++ than even I do (and I consider myself pretty damn good at C++). Maybe there's a compiler switch they use in their Makefiles that turns off that kind of auto-realigning...

8 Name: #!/usr/bin/anonymous : 2006-11-10 05:01 ID:yRl1iPbl

>>7
don't sweat it, your code is fine. heck, if you define operator float* in your vector class, you can ditch the explicit typecast for every function call, too.
9.2.12 Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that
later members have higher addresses within a class object. The order of allocation of non-static data members separated
by an access-specifier is unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3)
and virtual base classes (10.1).

9 Name: #!/usr/bin/anonymous : 2006-11-10 07:33 ID:6aGbySab

>>8

I thought operator overloading could only overload... operators. Can you really overload typecasts as if they're operators? I've never heard or seen that. If it's true, then I've said it before and I've said it again -- it's pretty much guaranteed I learn something new about C++ every week, for almost like 7 years now. Just last year I found out C++ has try/catch/throw style exceptions... I don't use them (I can only take so much visual clutter), but they're there if I want to.

Actually I did overload the array subscript operator for my Vector classes... so I could've really done, just out of semantic nitpickery (depends on the mood I'm in... sometimes I'm picky, sometimes I'm not):

glVertex3fv (&jointarray[i].pos[0]);

10 Name: #!/usr/bin/anonymous : 2006-11-11 08:09 ID:yRl1iPbl

>>9
Heh, yeah, C++ always has some new stuff, especially the obscure template magic you only tend to see in things like boost.
I have this in my vector class:

operator float*()
{
return (float*)this;
}
This thread has been closed. You cannot post in this thread any longer.