How to do this using templates in C++

Started by
31 comments, last by deathkrush 17 years, 9 months ago
There are tricks. They get tedious.

The easiest way to do it would be to steal boost::tuple's work.


Advertisement
Quote:Original post by Rebooted
A better solution than using an anonymous union was posted a while back. Search for "A slick trick in C++".


Wow, that trick looks complicated. I don't know if it will work, because my Vectors need to be POD-types.

Quote:Original post by Grain
Unless you have severe memory constraints It would be way easier to just use a vec4 all the time and if you don’t need the extra parameters just set them to 0


I will be using Vector2, Vector3 and Vector4 for texture coordinates, normals and colors, so they need to be separate classes with exactly 2, 3 or 4 values.

Quote:Original post by NotAYakk
There are tricks. They get tedious. The easiest way to do it would be to steal boost::tuple's work.


Cool, yet another solution! I'll take a look.

_goat,
I'm trying your solution right now. I was able to reuse a lot of code and specialize some of the comparison code for floats. Everything works well except for the fact that anonymous structs are not standard, so it probably won't work on GCC.

Rebooted,
Thanks for the non-member, non-friend suggestion. It magically works and the compiler optimizes everything. What would it take to have member functions as well? Do I still have to define all of them in each specialized class template?
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)
Quote:Original post by deathkrush
Wow, that trick looks complicated. I don't know if it will work, because my Vectors need to be POD-types.

Same here. A static const member shouldn't affect the vector's status as a POD type.
Quote:
Rebooted,
Thanks for the non-member, non-friend suggestion. It magically works and the compiler optimizes everything. What would it take to have member functions as well? Do I still have to define all of them in each specialized class template?
You will have too, yes. You might be able to use inheritance to get around this though.

However, why do you need member functions? It is generally recommended to prefer non-member functions where possible to increase encapsulation (this might seem backwards, but it makes the functions separate from the data type - the STL does this extensively). You only need member functions when you have to access private variables, and in this case x, y, z and w are public. Annoyingly, there are some operators that have to be members, like operator[].
Quote:Original post by Rebooted
However, why do you need member functions? It is generally recommended to prefer non-member functions where possible to increase encapsulation (this might seem backwards, but it makes the functions separate from the data type - the STL does this extensively). You only need member functions when you have to access private variables, and in this case x, y, z and w are public. Annoyingly, there are some operators that have to be members, like operator[].


Some functions like Normalize() and Length() will have to be member functions, otherwise I will have to do something crazy like VectorNormalize<float,3>(vec3) instead of vec3.Normalize(); The good thing is that I can write a common templated function that will do the actual calculation. To make it a member of every specialized class template, I will just define a member and call that 00beR function from the member.
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)
Quote:Original post by Rebooted
Some functions like Normalize() and Length() will have to be member functions, otherwise I will have to do something crazy like VectorNormalize<float,3>(vec3) instead of vec3.Normalize();

There is no need to provide the template parameters where they can be inferred. The only difference is vec3.Normalize() vs Normalize(vec3).
Well "a slick trick in c++" realy looks great, but it doesn't seem to be possible to put the dimension into a template parameter - you have to write Vector2, Vector3 and Vector4 (and more, if needed) classes. Or am i missing something?
Quote:Original post by deathkrush
Is this possible using templates:


Not with much gain. That said, this is quite possible using boost preprocessor!

#include <boost/preprocessor/repetition.hpp>#include <boost/preprocessor/tuple.hpp>#define ELEMENTS      4#define ELEMENT_NAMES (x,y,z,w)#define IMPLEMENT_VECTOR_ELEM(z,n,~) T BOOST_PP_TUPLE_GET(ELEMENTS,n,ELEMENT_NAMES);#define IMPLEMENT_VECTOR(z,n,~) template < typename T > \ class Vector ## n {                                     \      BOOST_PP_REPEAT(n,IMPLEMENT_VECTOR_ELEM,~)         \ };                                                      \ /*******************************************************/ BOOST_PP_REPEAT_FROM_TO(2,ELEMENTS,IMPLEMENT_VECTOR,~)//since we're using short names, lets be nice and clean them up:#undef IMPLEMENT_VECTOR#undef IMPLEMENT_VECTOR_ELEM#undef ELEMENT_NAMES#undef ELEMENTS


Another copy more closely matching the original post:

#include <boost/preprocessor/repetition.hpp>#include <boost/preprocessor/control/if.hpp>#define IMPLEMENT_VECTOR(z,n,~) template < typename T > \ class Vector ## n {                                     \     T x;                                                \     T y;                                                \     BOOST_PP_IF( BOOST_PP_GREATER_EQUAL(n,3) , T z; , ) \     BOOST_PP_IF( BOOST_PP_GREATER_EQUAL(n,4) , T w; , ) \ };                                                      \ /*******************************************************/ BOOST_PP_REPEAT_FROM_TO(2,4,IMPLEMENT_VECTOR,~)//since we're using short names, lets be nice and clean them up:#undef IMPLEMENT_VECTOR


Note: Examples have trailing whitespace after their backslashes to prevent "\ <newline>" from grokked by the forum and replacing it with "".
template<int n>stuct storage {  int elem;  storage():elem(0) {};};template<int n>struct n_ary:  nary<n-1>,  storage<n>{};template<>struct n_ary<0> {};template<int n>int& access(storage<n>& value) {  return value.elem;};typedef n_ary<4> Vector4;void test() {  n_ary<4> vec4;  access<1>(vec4) = 2;  printf("%d %d %d %d\n", access<1>(vec4), access<2>(vec4), access<3>(vec4), access<4>(vec4) );}


The above is where you might start writing up arbitrary vector code.

Getting "for_each" based addition and dot product is relatively simple.

Cross product might be a bit trickier. Especially if you go all the way up to wedge products. ;)


There was recently a huge amount of traffic on the sweng-gamedev mailing list about vector and matrix lbirary design. You should try to find an archive of it and sift through it.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Quote:Original post by _goat
I specialised the classes, using the little anonymous union/struct trick:

*** Source Snippet Removed ***



That is not standard compliant code, it's not portable C++ code.

This topic is closed to new replies.

Advertisement