[Insight-developers] Simplifying traits

Brad King brad.king@kitware.com
Fri, 23 Mar 2001 16:37:07 -0500 (EST)


Hello, all:

Here are some ideas to consider before deciding to throw out the use of
ScalarTraits an VectorTraits.  Our current approach is not the simplest
approach to using traits.

We can make traits easier to use.  Consider the following filter:

template <class TInputImage, class TOutputImage>
class MyFilter
{
public:
  typedef TInputImage InputImageType;
  typedef typename InputImageType::PixelType InputPixelType;
  typedef ScalarTraits<InputPixelType> PixelScalarTraits;
  typedef typename PixelScalarTraits::ScalarValueType
          PixelScalarValueType;
  
  inline static PixelScalarValueType& GetPixelScalar(PixelType& p)
    { return PixelScalarTraits::GetScalar(p); }

  inline static void SetPixelScalar(PixelType& p,
                                    const PixelScalarValueType& v)
    { PixelScalarTraits::SetScalar(p, v); }

  // ....
};

Note that the function definitions can be put in ImageToImageFilter and be
inherited into other filters.  Then, with minimal setup work, a filter
implementation can access a Pixel's scalar value like this:

PixelScalarValueType v = GetPixelScalar(myPixel);
  // do something to v.
SetPixelScalar(myPixel, v);

This is in place of the current code:

typename ScalarTraits<PixelType>::ScalarValueType v =
  ScalarTraits<PixelType>::GetScalar(myPixel);
  // do something to v.
ScalarTraits<PixelType>::SetScalar(myPixel, v);

Also, I have noticed that there are a bunch of extra ScalarTrait
specializations for more than the basic types.  An example is
"ScalarTraits< RGBPixel<float> >".  These should not be done, because if
someone wants to use an RGBPixel with a template argument other than those
defined in itkPixelTraits.h, they will have to figure out how to write
their own trait specialization for it.  Currently, this can be solved (I
think) by putting the proper typedefs (ValueType, etc) into RGBPixel and
letting the primary template of ScalarTraits handle it from there.

The "real" way to do such a specialization of the ScalarTraits for
RGBPixel would be to do a partial specialization:

template <typename TComponent>
class ScalarTraits< RGBPixel<TComponent> > { /* ... */ };

Unfortunately, not all of our compilers support partial specialization, so
we can't do this.

The other option is to not require scalar traits to be a speicalization of
ScalarTraits at all.  If instead we make such traits a template argument,
then any class can be defined and passed to the argument:

template <class TPixel, unsigned int VDimension,
          class TPixelTraits = ScalarTraits<TPixel> >
class Image
{
public:
  typedef TPixel PixelType;
  enum { Dimension = VDimension };
  typedef TPixelTraits PixelTraits;
  // ....
};

Then, filters could pull the Pixel traits out of their image template
parameters:

template <class TInputImage, class TOutputImage>
class MyFilter
{
public:
  typedef TInputImage InputImageType;
  typedef typename InputImageType::PixelTraits InputPixelTraits;
  // ... use traits as in previous MyFilter example.
};

Making traits a template argument is currently the approach that the Mesh
class uses.  It even encapsulates the "CellTraits" as a member of the
"MeshTraits" template argument.  We could make the same relationship for
the Image.  That is:

template <typename TPixel, unsigned int VDimension>
class DefaultImageTraits
{
public:
  typedef TPixel PixelType;
  enum { Dimension = VDimension };
  typedef DefaultPixelTraits<PixelType> PixelTraits;
  // ... other useful traits?
};

template <typename TPixel,
          unsigned int VDimension,
          class TImageTraits = DefaultImageTraits<TPixel, VDimension> >
class Image
{
public:
  typedef TImageTraits ImageTraits;
  typedef typename ImageTraits::PixelType   PixelType;
  typedef typename ImageTraits::PixelTraits PixelTraits;

  // ...
};

Assume that we have encapsulated both the current scalar and vector traits
into "DefaultPixelTraits".

Thoughts, anyone?
-Brad