www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Function template parameter inference from class template argument

reply Justin Johansson <procode adam-dott-com.au> writes:
D1.0

If you have a function template of one type parameter, T, that takes a class
template of the same type parameter, T, as an argument, then typical template
usage scenario goes like this: 

	/* Class template definition */
	class Foo(T) {
	}

	/* Function template definition */
	void bar(T)( Foo!(T) arg) {
		// ...
	}

	/* Instantiation usage */
	main()
	{
		auto foo = new Foo!(float)();	/* line A */
		bar!(float)( foo);			/* line B */
	}


Now since in the main function the compiler knows that T is float at line A, it
occurs to me that code noise could be reduced a bit if the compiler could
somehow deduce at line B that the function template parameter, T, is float
without it having to be explicitly written.

The instantiation usage would now look like this:

/* Less-noisy instantiation usage */
main()
{
	auto foo = new Foo!(float)();	/* line A */
	bar( foo);					/* line B */
}


The only problem is how then to write the function template definition so that
T can be defaulted to the class parameter, T, that accompanies Foo.

One idea I had, which of course doesn't work, is to define the function
template's argument with the auto keyword and then somehow figure out T from
the argument like so:
	
	/* Function template definition */
	void bar(T = typeof( arg))( auto arg) {
		// ...
	}


Since I'm getting used to finding cool features in D that always lets you do
stuff you never dreamed of,
and since I have a lot of template instantiation code,
it would be really neat to be able to reduce the noise a bit as outlined above.

Any ideas anybody? (Note D1.0)
		
Perhaps this is a no brainer and I just goofed up but have given up after a
spending way too much time on it thus far.

Thanks all.

Justin Johansson
Sep 23 2009
parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Wed, Sep 23, 2009 at 9:55 AM, Justin Johansson
<procode adam-dott-com.au> wrote:
 D1.0

 If you have a function template of one type parameter, T, that takes a cl=
ass template of the same type parameter, T, as an argument, then typical te= mplate usage scenario goes like this:
 =A0 =A0 =A0 =A0/* Class template definition */
 =A0 =A0 =A0 =A0class Foo(T) {
 =A0 =A0 =A0 =A0}

 =A0 =A0 =A0 =A0/* Function template definition */
 =A0 =A0 =A0 =A0void bar(T)( Foo!(T) arg) {
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// ...
 =A0 =A0 =A0 =A0}

 =A0 =A0 =A0 =A0/* Instantiation usage */
 =A0 =A0 =A0 =A0main()
 =A0 =A0 =A0 =A0{
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0auto foo =3D new Foo!(float)(); =A0 /* lin=
e A */
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bar!(float)( foo); =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0/* line B */
 =A0 =A0 =A0 =A0}


 Now since in the main function the compiler knows that T is float at line=
A, it occurs to me that code noise could be reduced a bit if the compiler = could somehow deduce at line B that the function template parameter, T, is = float without it having to be explicitly written.
 The instantiation usage would now look like this:

 /* Less-noisy instantiation usage */
 main()
 {
 =A0 =A0 =A0 =A0auto foo =3D new Foo!(float)(); =A0 /* line A */
 =A0 =A0 =A0 =A0bar( foo); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0/* line B */
 }


 The only problem is how then to write the function template definition so=
that T can be defaulted to the class parameter, T, that accompanies Foo.
 One idea I had, which of course doesn't work, is to define the function t=
emplate's argument with the auto keyword and then somehow figure out T from= the argument like so:
 =A0 =A0 =A0 =A0/* Function template definition */
 =A0 =A0 =A0 =A0void bar(T =3D typeof( arg))( auto arg) {
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// ...
 =A0 =A0 =A0 =A0}


 Since I'm getting used to finding cool features in D that always lets you=
do stuff you never dreamed of,
 and since I have a lot of template instantiation code,
 it would be really neat to be able to reduce the noise a bit as outlined =
above.
 Any ideas anybody? (Note D1.0)

 Perhaps this is a no brainer and I just goofed up but have given up after=
a spending way too much time on it thus far.
 Thanks all.

 Justin Johansson
class Foo(T) {} void bar(T : Foo!(U), U)(T t) {} void main() { auto foo =3D new Foo!(float)(); bar(foo); } :)
Sep 23 2009
parent reply Justin Johansson <procode adam-dott-com.au> writes:
Jarrett Billingsley Wrote:

 If you have a function template of one type parameter, T, that takes a class
template of the same type parameter, T, as an argument, then typical template
usage scenario goes like this:

        /* Class template definition */
        class Foo(T) {
        }

        /* Function template definition */
        void bar(T)( Foo!(T) arg) {
                // ...
        }

        /* Instantiation usage */
        main()
        {
                auto foo = new Foo!(float)();   /* line A */
                bar!(float)( foo);                      /* line B */
        }


 /* Less-noisy instantiation usage */
 main()
 {
        auto foo = new Foo!(float)();   /* line A */
        bar( foo);                                      /* line B */
 }
 class Foo(T) {}
 void bar(T : Foo!(U), U)(T t) {}
 
 void main()
 {
 	auto foo = new Foo!(float)();
 	bar(foo);
 }
 
 
 :)
Wow Jarret!!! So many words on my part to explain what I wanted and you came up with this just so, so coolly concise solution. It doesn't exactly look like a textbook solution so me thinks I can forgive myself for not figuring it out. (hey only 3 weeks into D now). I don't know if it would be pushing my luck or not, but is your concept generalizable to more parameters. In particular I want to be able to extend this so than bar() can return a generic type. So now I have this: class Foo(T) {} T2 bar(T : Foo!(U), U)(T t) { T2 x = ... return x; } void main() { auto foo = new Foo!(float)(); auto chu = bar!(double, float)( foo); // type of chu is double } and by analogy with the first problem I would like to instantiate like so: void main() { auto foo = new Foo!(float)(); auto chu = bar!(double)( foo); // be nice if float could be deduced from foo parameter // type of chu is double } Thanks muchly, -- Justin
Sep 23 2009
parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Wed, Sep 23, 2009 at 6:17 PM, Justin Johansson
<procode adam-dott-com.au> wrote:
 Wow Jarret!!! =A0So many words on my part to explain what I wanted and yo=
u came up with this just so, so coolly concise solution. =A0It doesn't exac= tly look like a textbook solution so me thinks I can forgive myself for not= figuring it out. (hey only 3 weeks into D now).
 I don't know if it would be pushing my luck or not, but is your concept g=
eneralizable to more parameters. =A0In particular I want to be able to exte= nd this so than bar() can return a generic type.
 So now I have this:

 class Foo(T)
 {}

 T2 bar(T : Foo!(U), U)(T t)
 {
 =A0T2 x =3D ...
 =A0return x;
 }

 void main()
 {
 =A0 =A0 =A0 =A0auto foo =3D new Foo!(float)();
 =A0 =A0 =A0 =A0auto chu =3D bar!(double, float)( foo);
 =A0 =A0 =A0 // type of chu is double
 }

 and by analogy with the first problem I would like to instantiate like so=
:
 void main()
 {
 =A0 =A0 =A0 =A0auto foo =3D new Foo!(float)();
 =A0 =A0 =A0 =A0auto chu =3D bar!(double)( foo); =A0 =A0// be nice if floa=
t could be deduced from foo parameter
 =A0 =A0 =A0 // type of chu is double
 }
class Foo(T) {} R bar(R, T : Foo!(U), U)(T t) { R r; return r; } void main() { auto foo =3D new Foo!(float)(); auto chu =3D bar!(double)(foo); pragma(msg, typeof(chu).stringof); } Make sure you have a newer compiler, though, as partial template specialization with IFTI was only introduced in DMD 1.038.
Sep 23 2009
parent Justin Johansson <procode adam-dott-com.au> writes:
Jarrett Billingsley Wrote:

 I don't know if it would be pushing my luck or not, but is your concept
generalizable to more parameters.  In particular I want to be able to extend
this so than bar() can return a generic type.
class Foo(T) {} R bar(R, T : Foo!(U), U)(T t) { R r; return r; } void main() { auto foo = new Foo!(float)(); auto chu = bar!(double)(foo); pragma(msg, typeof(chu).stringof); } Make sure you have a newer compiler, though, as partial template specialization with IFTI was only introduced in DMD 1.038.
Thanks again. I tried that before posting and it didn't work. Checked my DMD version .. missed out by 0.001 .. I had DMD 1.037. Upgraded just now to DMD 1.047 and your solution rocks yet again :-) <JJ/>
Sep 23 2009