Thread overview
Inferring function argument types from other argument types
Nov 13, 2012
Vijay Nayar
Nov 13, 2012
Vijay Nayar
November 12, 2012
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.
November 13, 2012
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.


November 13, 2012
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.
November 13, 2012
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.