Extend template instantiation for Python wrapping
The Python wrappers can handle C++ class templates, when they are able to guess which instantiations of those templates need to be wrapped. As an example, when array templates such as vtkSOADataArrayTemplate
are wrapped, Python classes are generated for vtkSOADataArrayTemplate<double>
, vtkSOADataArrayTemplate<long long>
, etc. The wrappers do this because they are aware of which types are used by vtkInstantiateTemplateMacro
(from vtkType.h
), and they know that VTK uses this macro to instantiate its array templates.
But what happens when the wrappers encounter a class template, but cannot guess how it will be instantiated? A recent example of this is vtkTemporalAlgorithm
in CommonExecutionModel
:
template <class AlgorithmT>
class vtkTemporalAlgorithm : public AlgorithmT
Wrapping instances of this template is easy in theory, but when we're wrapping vtkTemporalAlgorithm.h
, we don't yet know what what AlgorithmT
might be. We don't know that until we encounter an instantiation, e.g. in vtkTemporalStatistics.h
:
#include "vtkPassInputTypeAlgorithm.h"
#include "vtkTemporalAlgorithm.h"
class vtkTemporalStatistics : public vtkTemporalAlgorithm<vtkPassInputTypeAlgorithm>
Currently, vtkTemporalStatistics
is wrapped by using a preprocessor trick to fool the wrappers into seeing the following declaration instead, which removes vtkTemporalAlgorithm
and inherits directly from vtkPassInputTypeAlgorithm
:
class vtkTemporalStatistics : public vtkPassInputTypeAlgorithm
For more information on how this trick is implemented, see these comments in the header file. This trick comes at a cost, because the wrappers miss any APIs that were defined in vtkTemporalAlgorithm
.
To avoid this trick and its costs, we need to wrap vtkTemporalAlgorithm<vtkPassInputTypeAlgorithm>
during the wrapping of vtkTemporalStatistics.h
. In other words, when the wrappers see vtkTemporalAlgorithm<vtkPassInputTypeAlgorithm>
in vtkTemporalStatistics.h
, they have to find the definition of vtkTemporalAlgorithm
in vtkTemporalAlgorithm.h
, and then generate a wrapper class for vtkTemporalAlgorithm<vtkPassInputTypeAlgorithm>
. Implementing this would take some work, but it's doable. And it's also a very general answer to the question "how can the wrappers know which template instantiations need to be wrapped?".
As a general solution, this "automated instantiation" would have to handle the situations where the same template instantiation occurs multiple times. Take the simple example of the fictitious instantiation vtkMyClass<int>
. Even if this instantiation appears multiple times in the same header file, we only want to generate the class wrapper code for it once. This would be easy to do, since vtkWrapPython.c
would know if the class wrapper for vtkMyClass<int>
had already been generated. If vtkMyClass<int>
appears in more than one wrapped header, or perhaps even in different modules, then some kind of global mechanism would be needed to ensure that only one Python class object for vtkMyClass<int>
is created. Since module-loading occurs at runtime, the Python vtkMyClass
template object would have to keep a list of which instantiations of this template had been loaded.
Since a substantial (but measurable) amount of work would be needed to resolve this issue, it's worth asking, should we fix it? Currently, there is a documented work-around for vtkTemporalAlgorithm
(which entails hiding vtkTemporalAlgorithm from the wrappers). But if templated VTK filters become more widespread, then a more general solution (like the one discussed above) might become necessary.