[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;
}