[Insight-developers] Filter dispatch revisited

Brad King brad.king@kitware.com
Fri, 2 Feb 2001 09:46:23 -0500 (EST)


Hello all,

I have briefly looked at the dimension-specific filter implementation
problem, and realized that there is a much simpler solution than the one I
previously posted.  The example program below demonstrates the new
approach.  This will allow dimension and image-type implementation rules
to be arbitrarily added internally to any filter, without any help from
outside classes.

Hopefully, we will soon be submitting a real filter to Insight that takes
advantage of this approach.

-Brad

/**
 * Demonstration of filter dispatching.  The general problem is to provide
 * filters with specialized implementations for each dimension, but in
 * only one class, and without partial specialization.  Consider a filter
 * with separate methods for 2-d, 3-d, and N-d implementations.  We would
 * like to dispatch a call to the correct implementation from a single
 * Execute() call.
 *
 * The basic challenge here is that a filter that has been instantiated as
 * dimension 3, for example, still has execute methods for 2, 3, and N
 * dimensions.  If the 2-d Execute() is instantiated, it may have compiler
 * errors because it assumes that the class is instantiated for 2
dimensions.
 * This means we can't have an Execute() method which tests the dimension
 * at run-time and calls the appropriate Execute**d() method because it
will
 * instantiate all the Execute**d() methods, when only one will compile
 * properly.
 *
 * The solution presented below will allow a single Execute() call to
 * instantiate and call only the correct Execute**d() method for a
particular
 * filter instantiation.
 *
 * This has been tested successfully on
 *  - VC++ Service Pack 4
 *  - GCC
 *  - The Intel Compiler
 *  - MIPSpro
 */

#include <iostream>

//------------------------------------------------------------------

/**
 * An example filter.
 */
template <typename TInput, typename TOutput, unsigned long VDimension>
class ExampleFilter
{
public:
  typedef ExampleFilter<TInput, TOutput, VDimension> Self;
  // ....
  void Execute(void);

private:
  // Internal utility type to allow dimension-specific dispatch rules.
  // We could also use other properties (like image type) to make rules,
  // as long as each Execute() below has a full specialization of Dispatch
  // chosen.
  struct DispatchBase {};
  template <unsigned long>
  struct Dispatch: public DispatchBase {};
  
  void Execute(const DispatchBase&);
  void Execute(Dispatch<3>);
  void Execute(Dispatch<2>);
  // ....
  
};


/**
 * N-dimensional implementation of example filter.
 * The Dispatch parameter is not used.  It is just there to control
 * instantiation.
 */
template <typename TInput, typename TOutput, unsigned long VDimension>
void ExampleFilter<TInput, TOutput, VDimension>
::Execute(const DispatchBase&)
{
  std::cout << "N-d version" << std::endl;
}	 


/**
 * 2-dimensional implementation of example filter.
 * The Dispatch parameter is not used.  It is just there to control
 * instantiation.
 */
template <typename TInput, typename TOutput, unsigned long VDimension>
void ExampleFilter<TInput, TOutput, VDimension>
::Execute(Dispatch<2>)
{
  std::cout << "2-d version" << std::endl;
}


/**
 * 3-dimensional implementation of example filter.
 * The Dispatch parameter is not used.  It is just there to control
 * instantiation.
 */
template <typename TInput, typename TOutput, unsigned long VDimension>
void ExampleFilter<TInput, TOutput, VDimension>
::Execute(Dispatch<3>)
{
  std::cout << "3-d version" << std::endl;
}


/**
 * Main execute method called by the user of the filter.  In Insight, this
 * will actually be called by the filter's Update() method.
 * This just makes the call to the real method by instantiating the
 * appropriate Dispatch.
 *
 * Note that the ExampleFilter does not have to be templated over the
 * dimension if we could get it from one of the other parameters.
 * For example, we could have TInput::Dimension if TInput were supposed to
 * be an image type.
 */
template <typename TInput, typename TOutput, unsigned long VDimension>
void ExampleFilter<TInput, TOutput, VDimension>
::Execute(void)
{
  Execute(Dispatch<VDimension>());
}



int main(void)
{
  // Create a test filter for each dimensionality.
  ExampleFilter<int, char, 4> filter4d;
  ExampleFilter<int, char, 3> filter3d;
  ExampleFilter<int, char, 2> filter2d;

  // See if they each execute correctly.
  filter4d.Execute();  // Only instantiates N-d ExampleFilter::Execute()
  filter3d.Execute();  // Only instantiates 3-d ExampleFilter::Execute()
  filter2d.Execute();  // Only instantiates 2-d ExampleFilter::Execute()
  
  return 0;
}