D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 4265 - It should be possible to query template parameters with __traits
Summary: It should be possible to query template parameters with __traits
Status: RESOLVED WORKSFORME
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other All
: P2 enhancement
Assignee: No Owner
URL:
Keywords:
: 10890 (view as issue list)
Depends on:
Blocks:
 
Reported: 2010-06-02 20:33 UTC by nfxjfg
Modified: 2015-06-09 05:13 UTC (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description nfxjfg 2010-06-02 20:33:10 UTC
Consider you have

struct(T1, T2) Foo {
} 

alias Foo!(int, float) X;

You should be able to extract (int, float) from X.
Often it is possible to get the parameters indirectly from members, but there doesn't seem to be a way to do this in the general case.

I suggest:

__traits(getTemplateParameters, X)

which would yield  a (int, float) tuple.
Comment 1 Trass3r 2010-06-03 16:53:07 UTC
What would you use that for?
Comment 2 nfxjfg 2010-06-03 20:05:20 UTC
Trass3r: meta programming. It often happened to me that I wanted to get the template params. Sometimes I had to add alias declarations just to get access to them. I think this feature would make meta programming code simpler in some cases.

PS: the example above should start with:

struct Foo(T1, T2) {
}
Comment 3 Trass3r 2010-06-03 20:40:28 UTC
Well of course it's for metaprogramming.
But I can't imagine a usecase at the moment so I asked for some examples ;)
Comment 4 Andrej Mitrovic 2012-12-20 14:55:16 UTC
As a partial workaround if you know the original template a type was instantiated with you can use:

struct Foo(T1, T2)
{
}

alias Foo!(int, float) X;

template GetParams(R, alias X)
{
    static if (is(R x == X!T, T...))
    {
        alias T GetParams;
    }
}

void main()
{
    pragma(msg, GetParams!(X, Foo));
}

There's also an 'isTemplateInstance' now in std.traits.
Comment 5 Andrej Mitrovic 2012-12-22 15:09:13 UTC
I can have a pull ready soon for 2 traits:

1. Get the template out of the template instance (Foo!int => Foo)
2. Get the arguments used to instantiate the template (Foo!int => (int))

However I need some good names for these. I thought about using '__traits(getTemplateArgs, T)' and '__traits(getTemplateParent, T)', any better suggestions?
Comment 6 Andrej Mitrovic 2012-12-22 15:24:32 UTC
(In reply to comment #5)
> I can have a pull ready soon for 2 traits:
> 
> 1. Get the template out of the template instance (Foo!int => Foo)
> 2. Get the arguments used to instantiate the template (Foo!int => (int))
> 
> However I need some good names for these. I thought about using
> '__traits(getTemplateArgs, T)' and '__traits(getTemplateParent, T)', any better
> suggestions?

nazriel suggested:
'getTemplateName'
'getTemplateArgs' 

I think it's better because they line up nicely.
Comment 7 Andrei Alexandrescu 2013-03-24 05:30:25 UTC
C++ lacks this particular ability and makes up for it by requiring templates to define internal aliases for type parameters. However, this is more tenuous for value parameters and simply impossible for template template parameters (in our case alias parameters). This has led to certain contortions and limitations; based on that experience I think we should add this ability.
Comment 8 Andrej Mitrovic 2013-04-06 06:40:55 UTC
(In reply to comment #5)
> I can have a pull ready soon for 2 traits:

I managed to lose the branch where I implemented this. I think I only did it partially though.

@kenji: If you have this:

template T(Args...) { }
struct S(Args...) { }
alias Tint = T!int;
alias Sint = S!int;

How do you get to the 'S' declaration from the instance? I want to implement these traits:

static assert(is(__traits(getTemplateSymbol, SInt) == S));
static assert(is(__traits(getTemplateArgs, SInt) == int));

I've tried this in traits.c:

Dsymbol *s = getDsymbol(o);
TemplateInstace *ti = s->isTemplateInstance();

However that only works for Tint, and not for Sint. 's' is actually a StructDeclaration for Sint, not a TemplateInstance.
Comment 9 thelastmammoth 2013-06-23 18:26:08 UTC
(In reply to comment #4)
> As a partial workaround if you know the original template a type was
> instantiated with you can use:
> 
> struct Foo(T1, T2)
> {
> }
> 
> alias Foo!(int, float) X;
> 
> template GetParams(R, alias X)
> {
>     static if (is(R x == X!T, T...))
>     {
>         alias T GetParams;
>     }
> }
> 
> void main()
> {
>     pragma(msg, GetParams!(X, Foo));
> }
> 
> There's also an 'isTemplateInstance' now in std.traits.

I don't see it ? But I added it in https://github.com/D-Programming-Language/phobos/pull/1367.
Comment 10 thelastmammoth 2013-06-23 18:27:31 UTC
(In reply to comment #8)
> (In reply to comment #5)
> > I can have a pull ready soon for 2 traits:
> 
> I managed to lose the branch where I implemented this. I think I only did it
> partially though.
> 
> @kenji: If you have this:
> 
> template T(Args...) { }
> struct S(Args...) { }
> alias Tint = T!int;
> alias Sint = S!int;
> 
> How do you get to the 'S' declaration from the instance? I want to implement
> these traits:
> 
> static assert(is(__traits(getTemplateSymbol, SInt) == S));
> static assert(is(__traits(getTemplateArgs, SInt) == int));
> 
> I've tried this in traits.c:
> 
> Dsymbol *s = getDsymbol(o);
> TemplateInstace *ti = s->isTemplateInstance();
> 
> However that only works for Tint, and not for Sint. 's' is actually a
> StructDeclaration for Sint, not a TemplateInstance.


I made a pull request for this and other traits. It's in std.traits, which IMO is better than adding it to the compiler. 
https://github.com/D-Programming-Language/phobos/pull/1367
Comment 11 Andrej Mitrovic 2013-08-25 15:57:09 UTC
*** Issue 10890 has been marked as a duplicate of this issue. ***
Comment 12 Andrej Mitrovic 2014-04-28 14:05:41 UTC
There's now TemplateArgsOf and TemplateOf in std.traits:

-----
import std.traits;

struct Foo(T1, T2)
{
}

alias Foo!(int, float) X;

pragma(msg, TemplateArgsOf!X);  // (int, float)
-----