www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Default template arguments

reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
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 ...)
Nov 19 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
Nov 19 2012
parent reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
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?
Nov 19 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
Nov 19 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
Nov 19 2012
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Nov 19 2012
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
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.
Nov 19 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
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
Nov 19 2012
prev sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
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.
Nov 19 2012