Partial template function specialization

Lars T. Kyllingstad public at kyllingen.NOSPAMnet
Thu Aug 20 03:46:20 PDT 2009


Peter Alexander wrote:
> Hey all,
> 
> I'm considering learning D at the moment, and one thing that has bothered me in C++ is the lack of partial template function specializations. For example, you can create something like this:
> 
> template <class Field, class V>
> const Field norm(const V& v);
> 
> and you can specialize it:
> 
> template <>
> const double norm(const double& d)
> { return d < 0.0 ? -d : d; }
> 
> but you can't partially specialize it:
> 
> template <class Field>
> const Field norm(const Vector3<Field>& v)
> { /* return sqrt( ... ) */ }
> 
> Unless I'm mistaken...

You've come to the right place. D's template specialisation is very 
powerful, and when combined with implicit function template 
instantiation (IFTI) it makes for really beautiful code.

Disclaimer: You didn't say whether you use D1 or D2, but I use D2, so 
I'll give my answer in D2 code. It is highly likely it will also work in D1.

First of all, I don't know how it is in C++, but in D you rarely write 
function declarations without definitions. So unless you have a very 
general function body for your "general case", I'd simply drop it. If 
you have, the general case looks like this:

     Field norm(Field, V)(ref V v) { ... }

     // To call it:
     SomeDoublePrecisionVector v = ...;
     double n = norm!(double, SomeDoublePrecisionVector)(v);

Actually, because of IFTI, you can probably call it like

     double n = norm!(double)(v);

but there is a chance that the compiler will find it too much like the 
partially specialised case below.

The completely specialised case will look like this:

     double norm()(double d)
     {
         return d < 0.0 ? -d : d;
     }

     // To call it:
     double n = norm(-3.0);

Note that in the not-too-far future it is likely that non-templated 
functions will be allowed to overload against templated functions. When 
that happens, you can drop the first set of parentheses in the declaration.

I would write the partially specialised case like this:

     Field norm(Field)(ref Vector3!(Field) v) { ... }

     // To call it:
     Vector3!(real) myVector;
     real n = norm(myVector);

Yes, the compiler is smart enough to extract the Field from the 
Vector3!(Field) type. :) Because of IFTI you don't even have to specify 
it when calling norm().

In the above I have at least tried to stay D1 compatible. In D2 you can 
(arguably, of course) beautify your code a bit by writing Vector3!Float 
and so on. The parentheses are only needed when there are several 
template parameters.

For more info, check out http://www.digitalmars.com/d/2.0/template.html

-Lars


More information about the Digitalmars-d-learn mailing list