Thread overview | ||||||||
---|---|---|---|---|---|---|---|---|
|
February 23, 2017 template parameter inference and introspection | ||||
---|---|---|---|---|
| ||||
Is there any way to get a reference/alias to the instantiation of a template function that would be called, given certain parameters? I.e. to get the result of whatever template parameter inference (and overload resolution) has occurred? E.g. for some arbitrarily complex foo: static assert(__traits(compiles, foo(3))); alias fooWithInt = someMagic(foo(3)); so if foo was `void foo(T)(T t) {}` then `fooWithInt` would be `foo!int`, but if it was `void foo(Q = float, T = long)(T t)` then `fooWithInt` would be `foo!(float, int)` |
February 23, 2017 Re: template parameter inference and introspection | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | On Thursday, 23 February 2017 at 16:01:44 UTC, John Colvin wrote:
> Is there any way to get a reference/alias to the instantiation of a template function that would be called, given certain parameters? I.e. to get the result of whatever template parameter inference (and overload resolution) has occurred?
>
> E.g. for some arbitrarily complex foo:
>
> static assert(__traits(compiles, foo(3)));
> alias fooWithInt = someMagic(foo(3));
>
> so if foo was `void foo(T)(T t) {}` then `fooWithInt` would be `foo!int`, but if it was `void foo(Q = float, T = long)(T t)` then `fooWithInt` would be `foo!(float, int)`
I don't believe so, because foo(3) is a value (void), not a type like foo!int would be. You can't get it back after you've called the function. You would have to do something like:
alias fooWithInt = someMagic!foo(3);
Where someMagic constructs the alias to foo!int based on the type of arguments passed, or something like that.
|
February 23, 2017 Re: template parameter inference and introspection | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Thursday, 23 February 2017 at 18:21:51 UTC, Meta wrote:
> On Thursday, 23 February 2017 at 16:01:44 UTC, John Colvin wrote:
>> Is there any way to get a reference/alias to the instantiation of a template function that would be called, given certain parameters? I.e. to get the result of whatever template parameter inference (and overload resolution) has occurred?
>>
>> E.g. for some arbitrarily complex foo:
>>
>> static assert(__traits(compiles, foo(3)));
>> alias fooWithInt = someMagic(foo(3));
>>
>> so if foo was `void foo(T)(T t) {}` then `fooWithInt` would be `foo!int`, but if it was `void foo(Q = float, T = long)(T t)` then `fooWithInt` would be `foo!(float, int)`
>
> I don't believe so, because foo(3) is a value (void), not a type like foo!int would be. You can't get it back after you've called the function. You would have to do something like:
>
> alias fooWithInt = someMagic!foo(3);
>
> Where someMagic constructs the alias to foo!int based on the type of arguments passed, or something like that.
A quick and rough example I threw together. Annoyingly, I can't figure out a way to tell the compiler that I want to printout the symbol of fooWithInt, not call it without parens. The best I can do is print out its type.
void foo(T)(T t) {}
void foo(Q = float, T = long)(T t) {}
alias Typeof(alias v) = typeof(v);
template getInstantiation(alias f, T...)
{
import std.meta;
alias getInstantiation = f!(staticMap!(Typeof, T));
}
alias fooWithInt = getInstantiation!(foo, 3);
alias fooWithLong = getInstantiation!(foo, 3L);
void main()
{
pragma(msg, typeof(fooWithInt));
pragma(msg, typeof(fooWithLong));
}
|
February 24, 2017 Re: template parameter inference and introspection | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Thursday, 23 February 2017 at 18:33:33 UTC, Meta wrote: > On Thursday, 23 February 2017 at 18:21:51 UTC, Meta wrote: >> On Thursday, 23 February 2017 at 16:01:44 UTC, John Colvin wrote: >>> Is there any way to get a reference/alias to the instantiation of a template function that would be called, given certain parameters? I.e. to get the result of whatever template parameter inference (and overload resolution) has occurred? >>> >>> E.g. for some arbitrarily complex foo: >>> >>> static assert(__traits(compiles, foo(3))); >>> alias fooWithInt = someMagic(foo(3)); >>> >>> so if foo was `void foo(T)(T t) {}` then `fooWithInt` would be `foo!int`, but if it was `void foo(Q = float, T = long)(T t)` then `fooWithInt` would be `foo!(float, int)` >> >> I don't believe so, because foo(3) is a value (void), not a type like foo!int would be. You can't get it back after you've called the function. You would have to do something like: >> >> alias fooWithInt = someMagic!foo(3); >> >> Where someMagic constructs the alias to foo!int based on the type of arguments passed, or something like that. > > A quick and rough example I threw together. Annoyingly, I can't figure out a way to tell the compiler that I want to printout the symbol of fooWithInt, not call it without parens. The best I can do is print out its type. > > void foo(T)(T t) {} > void foo(Q = float, T = long)(T t) {} > > alias Typeof(alias v) = typeof(v); > > template getInstantiation(alias f, T...) > { > import std.meta; > > alias getInstantiation = f!(staticMap!(Typeof, T)); > } > > alias fooWithInt = getInstantiation!(foo, 3); > alias fooWithLong = getInstantiation!(foo, 3L); > > void main() > { > pragma(msg, typeof(fooWithInt)); > pragma(msg, typeof(fooWithLong)); > } Unfortunately that only works by accident of my example. A counterexample: T foo(Q = float, T = short)(T t) { return t; } alias Typeof(alias v) = typeof(v); template getInstantiation(alias f, T...) { import std.meta; alias getInstantiation = f!(staticMap!(Typeof, T)); } static assert(is(typeof(foo(3)) == int)); // ok static assert(is(typeof(getInstantiation!(foo, 3)(3)) == int)); // fails |
February 24, 2017 Re: template parameter inference and introspection | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | On Friday, 24 February 2017 at 11:17:46 UTC, John Colvin wrote:
> Unfortunately that only works by accident of my example. A counterexample:
>
> T foo(Q = float, T = short)(T t) { return t; }
>
> alias Typeof(alias v) = typeof(v);
>
> template getInstantiation(alias f, T...)
> {
> import std.meta;
>
> alias getInstantiation = f!(staticMap!(Typeof, T));
> }
>
> static assert(is(typeof(foo(3)) == int)); // ok
> static assert(is(typeof(getInstantiation!(foo, 3)(3)) == int)); // fails
This looks like VRP is kicking in when it shouldn't, or maybe it's a different bug. 3 should be typed as int by default unless we explicitly ask for something else.
|
February 24, 2017 Re: template parameter inference and introspection | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Friday, 24 February 2017 at 14:06:22 UTC, Meta wrote:
> On Friday, 24 February 2017 at 11:17:46 UTC, John Colvin wrote:
>> Unfortunately that only works by accident of my example. A counterexample:
>>
>> T foo(Q = float, T = short)(T t) { return t; }
>>
>> alias Typeof(alias v) = typeof(v);
>>
>> template getInstantiation(alias f, T...)
>> {
>> import std.meta;
>>
>> alias getInstantiation = f!(staticMap!(Typeof, T));
>> }
>>
>> static assert(is(typeof(foo(3)) == int)); // ok
>> static assert(is(typeof(getInstantiation!(foo, 3)(3)) == int)); // fails
>
> This looks like VRP is kicking in when it shouldn't, or maybe it's a different bug. 3 should be typed as int by default unless we explicitly ask for something else.
VRP propagation is what makes the call possible, but that's a distraction. The problem is that getInstantiation is setting Q to int and leaving T to be it's default type of short, which is not the same as if you just call with an int (which infers T from t and leaves Q as it's default float. Fundamentally, you can't assume the same order of runtime and template arguments.
|
Copyright © 1999-2021 by the D Language Foundation