Hi everybody,
I would like to use partial template specialization with template
parameters and optional template parameters, but I didn't find out
documentation about it and my compiler (g++) doesn't seem to accept
it : so how to proceed ?
For a piece of illustration here is my situation:
---------------------------------
// global
template< template <class> class, class >
class Z
{};
// e.g.
template< class, class Opt = O >
class X
{};
// specialized
template< class B, class Opt = O >
class Z< X<class, O>, B >
{};
OK, your question kept me thinking. My first reply was wrong, I didn't
clearly understood that the first parameter of Z (on which the
specialization is done) is a template class and not a class.
I think strictly speaking, in order to specialize on a template class,
like the first parameter of Z, you need the given argument to be such
a template class with one parameter. Your original definition of X
cannot be that, because it is just a template with 2 parameters and
there's no standard syntax in c++ to convolute it into what needed.
Also, to refine your question: suppose there was some way to define
such a partial specialization of Z, how would one ever use it? What
syntax is there to intanciate Z that would ever use that
specialization? There isn't any in standard c++.
You'd think something like: Z< X< ???, U >, B > could do that?
For example the following hipothetical syntax could do solve this. It
needs to support definitions of template of a template of a class.
Instead of X which is a 'template of a class', it would enable to
define X2 a 'template of a template of a class'.
* I think the default value given to the parameters doesn't affect
this problem anyway, so I'll just ommit that.
instead:
template< class T, class U > class X {...};
do:
template< class U > template< class T > class X2 {...};
or use X to define X2:
template< class U > template< class T > using X2 = X< T, U >;
in either case X2< U > is a 'template of a class'.
now X2 can be used to achieve the purpose (X can't do that directly at
all).
Z will be defined:
template< template< class > TT, class U >
class Z {};
and your required specialization defined:
template< class B, class U >
class Z< X2< U >, B > {};
an instanciation of Z that would use this specialization would be:
class D {};
class E {};
typedef Z< X2< D >, E > MyType;
//as said X2<D> is a template class with 1 parameter.
However AFAIK nothing like that is supported in the language.
I think there could be a workaround along the following guidelines.
This workaround requires some general library to handle "template-
functors". Below I give an implementation of two templates in such a
library that are needed for this example (TemplateFunctor1,
TemplateFunctor2, TemplateFunctorBind2).
I define a "template-functor" as a class that represents a template
class. It has a public template member "Instanciate" that can be
directly instanciated to give the represented template.
When defining Z and its partial specializations, the first parameter
of Z must be such a "template-functor" instead of an actual template.
Inside Z (and its specializations) one should use the "Instanciate"
member template of the given template-functor parameter.
class Z< class TF, class B >
{
//TF is a template-functor to achieve the actual template meant:
private: template< class T > TT = typename TF::Instanciate< T >;
//here use TT< ? > instead the original required parameter
}
if for example one would want to use Z with the following Y and E:
template< class T > class Y {};
class E {};
instead:
typedef Z< Y, E > MyType;
they have to use a template-functor that represent Y:
typedef Z< TemplateFunctor1< Y >, E > MyType;
and your problematic specialization:
template< class B, class Opt >
class Z< TemplateFunctorBind2< TemplateFunctor2< X >, Opt >, B >
{
private: template< class T > TT = X< T, Opt >;
//here use TT< ? > or directly X< T, Opt > where needed.
};
Then an instanciation like the following will use that specialization:
class D {};
class E {};
typedef Z< TemplateFunctorBind2< TemplateFunctor2< X >, D >, E >
MyType;
note the similarity of this with the above hipothetical syntax.
following are the templates from the suggested "template-functor
library" that were used above:
template< template< class > class TT > class TemplateFunctor1
{
public: template< class P > using Instanciate = typename TT< P1 >;
};
template< template< class, class > class TT > class TemplateFunctor2
{
public: template< class P1, class P2 > using Instanciate = typename
TT< P1, P2 >;
};
template< class Functor, class P2 >
class Bind2
{
public: template< class P1 > using Instanciate = typename
Functor::template Instanciate< P1, P2 >;
};
itaj