tags:

views:

289

answers:

1

I want to optimize my Vector and Matrix classes (which are class templates to be exact) using SIMD instructions and compiler intrinsics. I only want to optimize for the case where the element type is "float". Using SIMD instructions requires touching the data members. Since I don't want to be bothered with the trouble of maintaining two separate classes, I want to be able to enable/disable some data members based on the type of the template parameter. Another advantage of this approach, in case it's applicable, is that I can use the same code from the general case for functions that I don't want to write a specialization for. Therefore, what I want to achieve in pseudo code is:

template< typename T >
class Vector3 {
    if type( T ) == float:
        union {
            __m128 m128;
            struct {
                float x, y, z, pad;
            };
        };
   else
       T x, y, z;
   endif
};

I know conditional inclusion of members functions is possible via the use of Boost.enable_if or similar facilities. What I'm looking for though, is conditional inclusion of data members. As always, your help is very much appreciated. Other valid suggestions are also welcome.

Thanks.

+3  A: 

One solution that springs to mind is partially specialized templates, which is what Martin York posted, but with a twist.

I would recommend a special content_type-struct to supply the layout type, like so:

// content for non float types
template<typename T>
struct content_type {
   typedef typename T member_type;
   member_type x,y,z;
   member_type& X { return x; }
   // ...
   // if access to optional members is needed, better use CT_ASSERT or similar
   member_type& Pad { char assert_error_no_pad_here[0]; }
};

// content for float types
struct content_type<float> {
   typedef typename float member_type;
   member_type x, y, z, pad;
   member_type& X { return x; }
   // ...
   member_type& Pad { return pad; }
};

template<typename T>
class Vector3 {
    typedef typename content_type<T> layout_type;
    typedef typename content_type<T>::member_type member_type;

    layout_type _content;

  public:
    member_type& X { return _content.X(); }
    memmber_type& Pad { return _content.Pad(); }
};

// or maybe, if memory layout is not important, just inherit (watch for virtual members)
template<typename T>
class Vector3 : public content_type<T> {
    typedef typename content_type<T> layout_type;
    typedef typename content_type<T>::member_type member_type;
};

The advantage is you only have to write Vector3 with all of its logic once.

You need a moderately recent compiler to do that correctly, though (MSVC>7, gcc>3)

tabdamage
Excellent. Any idea how I should access those data members that are not part of the common denominator (e.g. "pad"). One approach is to disable their corresponding accessor member functions via Boost.enable_if in case those data members are not present. Thanks tabdamage.
Josh
i added a solution for that, but maybe boost::enable_if is a bit cleaner. The best solution depends on your actual use, to get the runtime logic as clean as possible, the type definitions need to be a little more complicated.
tabdamage