2

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.

Ash
  • 547
  • 5
  • 13

1 Answers1

5

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
  • 260
  • 1
  • 3
  • 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. – Ash Feb 21 '09 at 10:55
  • 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 Feb 21 '09 at 11:15