View mode: basic / threaded / horizontal-split · Log in · Help
November 19, 2012
Default template arguments
Suppose I have a template, for which I provide a default parameter type.  Is 
there any way of ensuring that this default will be respected unless the user 
explicitly requests an alternative type?

As an example, consider the following:

//////////////////////////////////////////
import std.stdio;

void printSize(T = real)(T x)
{
      writeln(x.sizeof);
}

void main()
{
      float x;
      x.printSize();
      x.printSize!float();
      x.printSize!real();
}
//////////////////////////////////////////

Here, a default type for T is given -- real -- but passing it a float overrides 
that default, which you can see because the printout of x.sizeof gives the size 
of a float instead of a real.  In other words it outputs

4
4
16

Instead, what I'd like is a way to specify the template parameters so that the 
type would be _real unless otherwise specified_ -- in other words, so that the 
above would output

16
4
16

Reading through http://dlang.org/templates-revisited.html I can't see an evident 
way to do this.  I've tried T:real in place of T = real, but the same behaviour 
results and in any case I don't think that syntax is intended for this kind of 
purpose.  (Actually, the given description of T:int as indicating "T must be int 
type" would suggest that T:real would force T to be a real in all circumstances, 
but that's not what happens ...)
November 19, 2012
Re: Default template arguments
Joseph Rushton Wakeling:

> Suppose I have a template, for which I provide a default 
> parameter type.  Is there any way of ensuring that this default 
> will be respected unless the user explicitly requests an 
> alternative type?

Take a look at how Complex does it:
https://github.com/D-Programming-Language/phobos/blob/master/std/complex.d

Bye,
bearophile
November 19, 2012
Re: Default template arguments
On 11/19/2012 04:47 PM, bearophile wrote:
> Take a look at how Complex does it:
> https://github.com/D-Programming-Language/phobos/blob/master/std/complex.d

Looking, but I don't think that's really what I'm looking for.  AFAICS Complex 
basically operates along these rules:

    -- if your input value(s) are floating point then use the (common) type of
       those values;

    -- if not, then use double

So if e.g. you replace those doubles in the complex() function with reals, then 
calling complex(1.0) will still get you back a Complex!double.

By contrast I'm looking for something like:

    -- if the user doesn't _explicitly specify the type_ then use real,
       regardless of the type of the input.

... or have I missed something?
November 19, 2012
Re: Default template arguments
Joseph Rushton Wakeling:

> ... or have I missed something?

Second try:

import std.stdio;

void printSize2(T)(T x) {
    writeln(T.stringof);
}

void printSize(T1 = void, T2 = real)(T2 x) {
    static if (is(T1 == void))
        printSize2!real(x);
    else
        printSize2!T1(x);
}

void main() {
    float x;
    x.printSize();       // shoud be real
    x.printSize!float(); // shoud be float
    x.printSize!real();  // shoud be real
}

Bye,
bearophile
November 19, 2012
Re: Default template arguments
Better:

import std.stdio;

private void printSizeHelper(T)(T x) {
    writeln(T.stringof);
}

void printSize(T1 = void, T2)(T2 x) {
    static if (is(T1 == void))
        printSizeHelper!real(x);
    else
        printSizeHelper!T1(x);
}

void main() {
    float x;
    x.printSize();
    x.printSize!float();
    x.printSize!real();
}


(Keeping the two functions separated is useful against template 
bloat.)

Bye,
bearophile
November 19, 2012
Re: Default template arguments
On 11/19/2012 09:44 AM, bearophile wrote:
> Better:
>
> import std.stdio;
>
> private void printSizeHelper(T)(T x) {
> writeln(T.stringof);
> }
>
> void printSize(T1 = void, T2)(T2 x) {
> static if (is(T1 == void))
> printSizeHelper!real(x);
> else
> printSizeHelper!T1(x);
> }
>
> void main() {
> float x;
> x.printSize();
> x.printSize!float();
> x.printSize!real();
> }
>
>
> (Keeping the two functions separated is useful against template bloat.)
>
> Bye,
> bearophile

I like that! :)

Is it possible or required to ensure that T1 is T2 in the static else 
clause?

Ali
November 19, 2012
Re: Default template arguments
On Monday, 19 November 2012 at 17:50:59 UTC, Ali Çehreli wrote:
> On 11/19/2012 09:44 AM, bearophile wrote:
>> Better:
>>
>> import std.stdio;
>>
>> private void printSizeHelper(T)(T x) {
>> writeln(T.stringof);
>> }
>>
>> void printSize(T1 = void, T2)(T2 x) {
>> static if (is(T1 == void))
>> printSizeHelper!real(x);
>> else
>> printSizeHelper!T1(x);
>> }
>>
>> void main() {
>> float x;
>> x.printSize();
>> x.printSize!float();
>> x.printSize!real();
>> }
>>
>>
>> (Keeping the two functions separated is useful against 
>> template bloat.)
>>
>> Bye,
>> bearophile
>
> I like that! :)
>
> Is it possible or required to ensure that T1 is T2 in the 
> static else clause?
>
> Ali

Should check if it's implicit convertable. Most of the times you 
use this pattern, you'll get an template error down in 
printSizeHelper, but you want your template hierarchy to fail as 
soon as possible.
November 19, 2012
Re: Default template arguments
On 11/19/2012 06:44 PM, bearophile wrote:
> private void printSizeHelper(T)(T x) {
>      writeln(T.stringof);
> }
>
> void printSize(T1 = void, T2)(T2 x) {
>      static if (is(T1 == void))
>          printSizeHelper!real(x);
>      else
>          printSizeHelper!T1(x);
> }

Thanks for the suggestion! :-)

Now I think of it, is there anything wrong with,

void printSizeHelper(T)(T x)
{
      writeln(x.sizeof);
}

void printSize(T1 = real, T2)(T2 x)
      if(is(T2 : T1))
{
      printSizeHelper!T1(x);
}

... bar some extra safety constraints, perhaps?

I have a feeling I'd considered that solution at some point but had put it aside 
because I was feeling sure there must be a way that didn't involve creating an 
extra template parameter.
November 19, 2012
Re: Default template arguments
Tobias Pankrath:

> Most of the times you use this pattern, you'll get an template 
> error down in printSizeHelper, but you want your template 
> hierarchy to fail as soon as possible.

Right, my code wasn't complete, it's just a draft. It needs some 
template constraints.

Bye,
bearophile
Top | Discussion index | About this forum | D home