November 19, 2012
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
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
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
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
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
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
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
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
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