www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Inferring function argument types from other argument types

reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
Suppose that I've got a struct which internally defines a number of types:

     struct Foo(_T1, _T2)
     {
         alias _T1 T1;
         alias _T2 T2;
         T1 a;
         T2 b;
     }

... and now I want to define a function which takes as input an instance of one 
of these structs, and a variable of type T1.

I tried the following:

     T func(FooT, T = FooT.T1)(FooT foo, T x)
     {
         return x * foo.a;
     }

but found that the type of whatever I was passing would override the default: 
e.g. if I called func(fooInstance, 1) then the second argument would be 
interpreted as an int even though Foo.T1 is size_t.

I also tried,

     T func(FooT, T : FooT.T1)(FooT foo, T x)
     {
         return x * foo.a;
     }

but this generates a different error: "no property 'T1' for type 'FooT'".  I 
tried replacing FooT with alias FooT to no avail.

Obviously I could get round the problems of the first example with something 
based around CommonType etc. but I'm just wondering if it's possible to make an 
argument dependent on another template parameter in the way I'm looking for
here.
Nov 12 2012
parent reply "Vijay Nayar" <madric gmail.com> writes:
I believe this question was asked before, but here is the 
solution again.

struct Foo(_T1, _T2)
{
   alias _T1 T1;
   alias _T2 T2;
   T1 a;
   T2 b;
}

FooT.T1 func(FooT, T)(FooT foo, T x)
   if (is(FooT.T1) && is(T : FooT.T1))
{
   return x * foo.a;
}

void main() {
   auto foo = Foo!(size_t, string)(8, "bobcat");
   int value = 3;
   assert(foo.func(value) == 24);
   assert(is(typeof(foo.func(value)) == size_t));
}

  - Vijay

On Monday, 12 November 2012 at 12:42:31 UTC, Joseph Rushton 
Wakeling wrote:
 Suppose that I've got a struct which internally defines a 
 number of types:

     struct Foo(_T1, _T2)
     {
         alias _T1 T1;
         alias _T2 T2;
         T1 a;
         T2 b;
     }

 ... and now I want to define a function which takes as input an 
 instance of one of these structs, and a variable of type T1.

 I tried the following:

     T func(FooT, T = FooT.T1)(FooT foo, T x)
     {
         return x * foo.a;
     }

 but found that the type of whatever I was passing would 
 override the default: e.g. if I called func(fooInstance, 1) 
 then the second argument would be interpreted as an int even 
 though Foo.T1 is size_t.

 I also tried,

     T func(FooT, T : FooT.T1)(FooT foo, T x)
     {
         return x * foo.a;
     }

 but this generates a different error: "no property 'T1' for 
 type 'FooT'".  I tried replacing FooT with alias FooT to no 
 avail.

 Obviously I could get round the problems of the first example 
 with something based around CommonType etc. but I'm just 
 wondering if it's possible to make an argument dependent on 
 another template parameter in the way I'm looking for here.
Nov 13 2012
parent reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 11/13/2012 05:05 PM, Vijay Nayar wrote:
 I believe this question was asked before, but here is the solution again.
The actual reality of what I'm trying to do is slightly more complex: it's more like struct Foo(_T1, _T2) { alias _T1 T1; alias _T2 T2; // etc. } FooT.T1 func(FooT, T)(FooT foo, T x) { return func2(x); } ... where func2() is also a templated function, and it's important that it take a type of FooT.T1 and not T. So, I can't see what the solution is apart from casting x to FooT.T or explicitly indicating FooT.T1 as a template parameter for func2.
Nov 13 2012
parent "Vijay Nayar" <madric gmail.com> writes:
Ok, I get it.

My understanding is that you have basically two options.
   * If you want the function to be called with any implicitly
     castable type, then you must cast it in the function.
   * If you only want the function to accept the one type,
     then use is(T == FooT.T1) and you must cast the input
     the function.

However, all this feels like an over complication and round-about 
way of
doing things.  If you have exact types that must be specified in 
the
struct, you probably don't want an external template at all.  
Simply place
the function in the struct.

struct Foot(_T1, _T2) {
   ...
   _T1 func(_T1 x) {
     return func2(x);
   }
}

  - Vijay

On Tuesday, 13 November 2012 at 16:39:55 UTC, Joseph Rushton 
Wakeling wrote:
 On 11/13/2012 05:05 PM, Vijay Nayar wrote:
 I believe this question was asked before, but here is the 
 solution again.
The actual reality of what I'm trying to do is slightly more complex: it's more like struct Foo(_T1, _T2) { alias _T1 T1; alias _T2 T2; // etc. } FooT.T1 func(FooT, T)(FooT foo, T x) { return func2(x); } ... where func2() is also a templated function, and it's important that it take a type of FooT.T1 and not T. So, I can't see what the solution is apart from casting x to FooT.T or explicitly indicating FooT.T1 as a template parameter for func2.
Nov 13 2012