function template specialization question D vs. C++

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sun Jan 14 02:14:50 UTC 2018


On Sunday, January 14, 2018 01:02:46 kdevel via Digitalmars-d-learn wrote:
> On Sunday, 14 January 2018 at 00:30:37 UTC, Nicholas Wilson wrote:
> > The usual way to do what you are trying to do is with template
> > constraints.
> >
> > void foo(T)() if (is(T== float)) { ...}
>
> Thanks. That works but looks a bit ugly. Am I right that I have
> to leave out the primary (unconstrained) template?

If you're using template constraints rather than template specializations,
then you can't have any unconstrained templates. A given argument will have
to compile with exactly one overload of the template - or none, if you don't
want it to compile with any of them. However, you can also specialize
internally via static if, which may or may not be better, depending on what
you're trying to do. e.g.

void foo(T)(T arg)
{
    static if(is(T == int))
    {
        // do something
    }
    else static if(is(T == float))
    {
        // do something else
    }
    else
    {
        // do something with the rest...
    }
}

To do the same thing with overloaded templates, you'd need to do

void foo(T)(T arg)
    if(is(T == int))
{
    // do something
}

void foo(T)(T arg)
    if(is(T == float))
{
    // do something else
}


void foo(T)(T arg)
    if(!is(T == int) && !is(T == float))
{
    // do something with the rest...
}

In general, at this point, it's considered best practice to try and make the
top-level constraints as general as possible and specialize internally
rather than overloading at the top-level (unless the overloads really are
disjoint - e.g. they take a different number of arguments). Doing all of the
specializations at the top-level has made the documentation for some of the
functions in Phobos harder to read through and made error messages worse,
since you have to dig through a bunch of different template constraints,
whereas by making the top-level constraints more general and trying to push
the specializations inside with static ifs, things become more manageable.

Also, if you want to T to be implicitly convertibly to the given type, then
use : instead of ==, and if you don't care about the type modifiers such as
const, then use std.traits.Unqual. e.g.

void foo(T)(T arg)
   if(is(T == float))
{
}

will not compile if the argument is a const float, whereas

void foo(T)(T arg)
   if(is(Unqual!T == float))
{
}

will. And in the case of the static if above, a const float would take the
else branch. So, Unqual would probably be merited there as well. For better
or worse, D templates tend to end up with a fair bit of metaprogramming used
with constraints and static ifs. You're not going to see very many cases of
templates without any constraints or specializations (and most folks don't
use specializations). You get by far the best control using template
constraints, and you can improve error messages by making it so that
arguments that wouldn't compile with the template fail the constraint
instead of generating an error from inside the template.

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list