Boost logo

Boost :

From: Geoffrey Irving (irving_at_[hidden])
Date: 2006-09-21 13:33:32


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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk