
On Thu, Sep 21, 2006 at 06:18:10PM +0200, Theodore Papadopoulo wrote:
On Thu, 2006-09-21 at 08:54 -0400, Michael Fawcett wrote:
You can get around this using something like this:
template< typename T > struct Vector4 {
typedef size_t size_type;
private:
typedef T Vector4<T>::* const vec[4];
static const vec v;
public:
T x, y, z, w;
Vector4(T _x = 0, T _y = 0, T _z = 0, T _w = 0): x(_x), y(_y), z(_z), w(_w) {}
const T& operator[](size_type i) const { return this->*v[i]; }
T& operator[](size_type i) { return this->*v[i]; }
};
template< typename T > const typename Vector4<T>::vec Vector4<T>::v = { &Vector4<T>::x, &Vector4<T>::y, &Vector4<T>::z, &Vector4<T>::z };
Here's the original discussion from gamedev.net http://www.gamedev.net/community/forums/topic.asp?topic_id=261920
This wasn't written by me, I just remembered it from there and thought it might be interesting to you.
This code is much too hard for the compiler to optimize. In order to handle a loop like for(int i=0;i<n;i++) f(V[i]); where n at runtime could be either 2 or 3, the compiler would have to independently determine the identity vec[i+1] = vec[i]+1. There's no way that would happen on any compiler now or in the immediate future.
Interesting ! But I would certainly prefer the straightforward array implementation and an enum {X,Y,Z,Z} that allows the notation
V[X] or V(X) (depending on your preference). The only fear I may have with your proposal is that by having complicated accesses, the compiler might not be able to do some optimizations.
This scheme means you can't have a vector called X, which happens to be one of the most commonly used vector names in my code (X for position, V for velocity). I don't think there's any reason to overthink this. The simple scheme works: template<class T> class vector3 { public: T x,y,z; vector3() { assert(&z == &x+3); } T& operator[](unsigned i) {assert(i<3);return (&x)[i];} }; It can probably even be considered standard compliant: if the assert doesn't hit, I'm pretty sure the standard guarantees that the code is correct. If I run the following code through gcc 4.0.1 vector3<float> X; X.y=3; X[2]=4; // critical line std::cout<<X.x; the compiler unpacks X into fields and complains about X$x being used uninitialized iff I comment out the critical line, so there shouldn't be any penalty to the existence of operator[] unless you use it in on a given vector. As a side note, is it possible to write that with a STATIC_ASSERT? Geoffrey