templates for geometric classes?

Started by
17 comments, last by RedDrake 16 years, 6 months ago
Hi all, I'm quite finished with the rewriting of my geometric classes core (rays, vectors and matrics). While looking the web for references and implementation examples I've noticed that many people use templates to do it. Brfore starting to implement the other classes of the raytracer I would like to know if this is all that common and if the advantages are really so high. I mean, actually I simply use a #define to set float or double, and I will make use of sse whenever it could help. I don't think I will ever need something different than float or doubles, but perhaps I'm underrating something. Would that make it difficult to optimize the code for SSE? (I'm asking because I never used templates in the last few years and I don't remember all the details). What do you suggest? Thank you!
Advertisement
About the sse optimization, its just a matter of specializing the <float> versions to do sse with floats, so optimization won't be hindered by templates. Plus, integer vectors might be useful for things like pixel coordinates. If you don't want to write the extra <> when declaring an object, you can always typedef, e.g.
typedef Vector2<UInt32> PixelCoords;ortypedef Vector2<Float32> Vector2f;

etc..
I believe you have nothing to lose by templatizing your classes, you will only benefit.
Thank you, it sounds cool to me, but I'm concerned about a couple of issues. For example, am I allowed to memory align a template (required for sse) only for those types that require it? As soon as I go home I will give a read to my C++ reference book...
Other thoughts about the topic?

Thank you again!
Just tried this in g++ 4.1.2 :

#include <iostream>typedef float Float32;typedef double Float64;template<typename T>struct Vector3{public:	T x;	T y;	T z;	Vector3(){};	Vector3(T a_x, T a_y, T a_z) : x(a_x), y(a_y), z(a_z){};};template<>struct  __attribute__((aligned(32))) Vector3<Float32>{public:	Float32 x;	Float32 y;	Float32 z;	Vector3(){};	Vector3(Float32 a_x, Float32 a_y, Float32 a_z) : x(a_x), y(a_y), z(a_z){};	};int main(){	Vector3<Float32> v1;	Vector3<Float64> v2;	std::cout << sizeof(v1) << std::endl;	return 0;};


sizeof(v1) turns out to be 32 and sizeof(v2) is 24, so the alignment works for the specialization :) I don't have VS 2005 installed atm, but i 'm pretty sure it won't have a problem.
As long as your compiler/optimizer is pretty decent (gcc, msvc and icc all fall into this category), there's no real disadvantage to using templates, and they certainly increase your flexibility.

The examples shown already are good, but you can even go further:
template<unsigned int N, typename T>class Vector{  T m_data[N];  ...}

It's even possible to support ".x", ".yx", etc. swizzles with clever enough coding, but honestly I personally prefer the indexed approach... something like:
Vector<3, float> a;a(0,1,2) = a(2,1,0);

It's very easy to support, fully efficient and allows "dynamic" swizzles when you need them, which actually come in very handy. You can of course support this in addition to the other syntax if desired.

To answer your other question: yes you can most certainly align the data member of your class just like you'd do it if it wasn't templated.

Cheers, and good luck!
Quote:Original post by AndyTX
As long as your compiler/optimizer is pretty decent (gcc, msvc and icc all fall into this category),

Well, I don't really plan to support other compilers anyway...

Quote:The examples shown already are good, but you can even go further:
template<unsigned int N, typename T>class Vector{  T m_data[N];  ...}

It's even possible to support ".x", ".yx", etc. swizzles with clever enough coding, but honestly I personally prefer the indexed approach... something like:
Vector<3, float> a;a(0,1,2) = a(2,1,0);


Interesting :-) Currently I provide three methods to access data: through x, y, z and w members, through index and through sse variables when available. I hope to be able to keep all them, and (why not?) add your idea :-)
Instead I won't provide templated vector size: only 2 and 3 dimensions (with the 3d actually holding 4 vars, the 4th being the w element).

Quote:
To answer your other question: yes you can most certainly align the data member of your class just like you'd do it if it wasn't templated.

Cheers, and good luck!


Good to know and thank to both of you!

After a bit of research I've found that I may have problems using templates with my current vectors and matrix structure:
	class SIMD_ALIGN vector4	{	public:		union		{			struct			{				real x, y, z, w;			};			real values[4];	#ifdef USE_SIMD			SIMD_VALUE ssevalue;	#endif //USE_SIMD		};		vector4() : x(0), y(0), z(0), w(0) {}		vector4(real _x, real _y, real _z) : x(_x), y(_y), z(_z), w(0) {}		vector4(real _x, real _y, real _z, real _w) : x(_x), y(_y), z(_z), w(_w) {}		vector4(const vector4 &src) : x(src.x), y(src.y), z(src.z), w(src.w) {}


I know that this trick is not standard and may not be supported by some compilers, but I find it extremely useful and both VC++ and gcc do support it (perhaps also ICC does...).
But the following template doesn't work:
	template<typename T> 	class vector3	{	public:		union		{			struct			{				T x, y, z, w;			};			T values[4];		};	public:		void vector4() {}		void vector4(const T v) : x(v), y(v), z(v) {}	};

VC++ says:
"error C2327: 'glgeom::vector3<T>::<unnamed-tag>::x' : is not a type name, static, or enumerator"

I don't know yet if this relates to what I've read elsewhere that a union doesn't allow any of its member to have a non-trivial contructor, assigment etc, but if this is the case, then writing a templatized math library for my RT has no longer a point. I will think a bit more about this, because on one hand the very idea of having templates is tempting, but on the other side I'm not writing a generic vector/matrix library, just one for my RT, so gaining in flexibility with supported types while loosing flexibility in member access modes is not really what I want.
In addition, I'm under the impression that optimizing operations for SIMD types would require me to specialize lot of methods for floats (SSE) and doubles (SSE2). Integer may need some specialization too (SSE3?).

I'm still doing research and designing the RT classes, and since I've not much spare time to spend for this personal project, I've still quite some time before starting to implement it.
Any suggestion?
The second piece of code compiled cleanly in g++ 4.1.2 with -Wall, after changing the name of the constructors from vector4 to vector3. It seems you had a typo :P (or i am missing something :D)

-EDIT: I also had to remove the keyword "void" before the constructors, to eliminate the following errors (in g++):

"Test.cpp:15: error: return type specification for constructor invalid"
"Test.cpp:16: error: return type specification for constructor invalid"
Thank you, the void before the contructor was a desperate attempt to figure out what was happening. The vector3, instead, was indeed a typo :-)

Many of the errors were due to me mixing up things, now it compiles. I'm still skeptical about using templates, the bad thing being the fact that they are really powerful, so I cannot decide.
Well, question for those who know templates better than me. If I wanted to use a class with the shown vector4, could I use it, ot the union would prevent me from using non-trivial objects?

EDIT: perhaps this is an answer:
class complex{	float real, img;	complex(): real(0.0), img(0.0) {}	complex(float r, float i) : real(r), img(i) {}};vector4<complex> vc;


won't compile. VC++ issues the following error:
"error C2620: member 'qlgeom::vector4<T>::values' of union 'qlgeom::vector4<T>::<unnamed-tag>' has user-defined constructor or non-trivial default constructor"

End of the story?
Quote:
In addition, I'm under the impression that optimizing operations for SIMD types would require me to specialize lot of methods for floats (SSE) and doubles (SSE2). Integer may need some specialization too (SSE3?).


Yes, but this has nothing to do with using templates. If you wanted to optimize for SIMD for say N different data types without using templates, you should write N different optimized classes from the start of your project. With templates, instead, you write one class, and you use it with any data type you want. Then you can specialize for those datatypes for which you need the optimizations, whenever you need it, without having duplicate code from the start of your project.

However, i am no c++ expert, not even experienced, so i would also like to read other people's views on the subject.

This topic is closed to new replies.

Advertisement