Thread overview
Get class type parameters at compile time
Dec 13, 2012
js.mdnq
Dec 13, 2012
Philippe Sigaud
Dec 14, 2012
js.mdnq
Dec 14, 2012
bearophile
Dec 14, 2012
Philippe Sigaud
Dec 15, 2012
js.mdnq
Dec 15, 2012
Philippe Sigaud
Dec 17, 2012
js.mdnq
Dec 17, 2012
js.mdnq
December 13, 2012
I need to get the number of type parameters of a class at compile time:


class a(T1, T2, ...)
{
   static if (a.TypeInfo.NumParameters == 1)
      ....
   else
      ....

}

Is this possible?
December 13, 2012
On Thu, Dec 13, 2012 at 11:56 AM, js.mdnq <js_adddot+mdng@gmail.com> wrote:

> I need to get the number of type parameters of a class at compile time:
>
>
> class a(T1, T2, ...)
> {
>    static if (a.TypeInfo.NumParameters == 1)
>       ....
>    else
>       ....
>
> }
>
> Is this possible?
>

Yes, it's possible:

// Inside the class, it's easy:
class Test(T...)
{
    enum num = T.length;// T is known here
}

// Outside the class, it's a bit tricky, but quite doable:
template TemplateArity(Type)
{
    enum T = Type.stringof;
    mixin("alias " ~ T ~ " U;");
    static if (is(Type _ == U!Args, Args...))
        enum TemplateArity = Args.length;
    else
        enum TemplateArity = -1;
}

void main()
{
    alias Test!(int, double, string) T;

    assert(T.num == 3); // Internal knowledge
    assert(TemplateArity!T == 3); // External deduction
}


December 14, 2012
On Thursday, 13 December 2012 at 22:10:40 UTC, Philippe Sigaud
wrote:
> On Thu, Dec 13, 2012 at 11:56 AM, js.mdnq <js_adddot+mdng@gmail.com> wrote:
>
>> I need to get the number of type parameters of a class at compile time:
>>
>>
>> class a(T1, T2, ...)
>> {
>>    static if (a.TypeInfo.NumParameters == 1)
>>       ....
>>    else
>>       ....
>>
>> }
>>
>> Is this possible?
>>
>
> Yes, it's possible:
>
> // Inside the class, it's easy:
> class Test(T...)
> {
>     enum num = T.length;// T is known here
> }
>
> // Outside the class, it's a bit tricky, but quite doable:
> template TemplateArity(Type)
> {
>     enum T = Type.stringof;
>     mixin("alias " ~ T ~ " U;");
>     static if (is(Type _ == U!Args, Args...))
>         enum TemplateArity = Args.length;
>     else
>         enum TemplateArity = -1;
> }
>
> void main()
> {
>     alias Test!(int, double, string) T;
>
>     assert(T.num == 3); // Internal knowledge
>     assert(TemplateArity!T == 3); // External deduction
> }

cool, I'll need it outside the class. Thanks.
December 14, 2012
Philippe Sigaud:

> template TemplateArity(Type)
> {
>     enum T = Type.stringof;
>     mixin("alias " ~ T ~ " U;");
>     static if (is(Type _ == U!Args, Args...))
>         enum TemplateArity = Args.length;
>     else
>         enum TemplateArity = -1;
> }
>
> void main()
> {
>     alias Test!(int, double, string) T;
...
>     assert(TemplateArity!T == 3); // External deduction
> }

Fit to be added to Phobos?

Bye,
bearophile
December 14, 2012
On Fri, Dec 14, 2012 at 1:18 AM, bearophile <bearophileHUGS@lycos.com>wrote:

>
> Fit to be added to Phobos?
>

Maybe, I don't know. People seem to ask for this quite regularly.

Here is a slightly improved version, what do you think?

template isTemplatedType(Type...) if (Type.length == 1)
{
    mixin("alias " ~ Type[0].stringof ~ " U;");
    static if (is(Type[0] _ == U!Args, Args...))
        enum isTemplatedType = true;
    else
        enum isTemplatedType = false;
}

template TemplateArity(Type...) if (Type.length == 1 &&
isTemplatedType!(Type[0]))
{
    mixin("alias " ~ Type[0].stringof ~ " U;");
    static if (is(Type[0] _ == U!Args, Args...))
        enum TemplateArity = Args.length;
}

template TemplateArgs(Type...) if (Type.length == 1 &&
isTemplatedType!(Type[0]))
{
    mixin("alias " ~ Type[0].stringof ~ " U;");
    static if (is(Type[0] _ == U!Args, Args...))
        alias Args TemplateArgs;
}

void main()
{
    alias Tuple!(int, double) T;
    writeln(TemplateArity!T);
    writeln(TemplateArgs!T.stringof);
    writeln(isTemplatedType!T);
}


December 15, 2012
On Friday, 14 December 2012 at 20:14:29 UTC, Philippe Sigaud wrote:
> On Fri, Dec 14, 2012 at 1:18 AM, bearophile <bearophileHUGS@lycos.com>wrote:
>
>>
>> Fit to be added to Phobos?
>>
>
> Maybe, I don't know. People seem to ask for this quite regularly.
>
> Here is a slightly improved version, what do you think?
>
> template isTemplatedType(Type...) if (Type.length == 1)
> {
>     mixin("alias " ~ Type[0].stringof ~ " U;");
>     static if (is(Type[0] _ == U!Args, Args...))
>         enum isTemplatedType = true;
>     else
>         enum isTemplatedType = false;
> }
>
> template TemplateArity(Type...) if (Type.length == 1 &&
> isTemplatedType!(Type[0]))
> {
>     mixin("alias " ~ Type[0].stringof ~ " U;");
>     static if (is(Type[0] _ == U!Args, Args...))
>         enum TemplateArity = Args.length;
> }
>
> template TemplateArgs(Type...) if (Type.length == 1 &&
> isTemplatedType!(Type[0]))
> {
>     mixin("alias " ~ Type[0].stringof ~ " U;");
>     static if (is(Type[0] _ == U!Args, Args...))
>         alias Args TemplateArgs;
> }
>
> void main()
> {
>     alias Tuple!(int, double) T;
>     writeln(TemplateArity!T);
>     writeln(TemplateArgs!T.stringof);
>     writeln(isTemplatedType!T);
> }

Oops ;/ How do I get the number of type arguments if I don't know them yet? I know this sort of seems wrong but somehow, to know how to alias the class I need to know it's number of arguments. (I don't think it makes too much sense with the type system but not sure how to solve the following problem without it:

http://forum.dlang.org/thread/wacupbnlqgrfhaebdssd@forum.dlang.org#post-yhhtuojlsgiykyrfhngl:40forum.dlang.org)
December 15, 2012
>
> Oops ;/ How do I get the number of type arguments if I don't know them yet? I know this sort of seems wrong but somehow, to know how to alias the class I need to know it's number of arguments. (I don't think it makes too much sense with the type system but not sure how to solve the following problem without it:
>
> http://forum.dlang.org/thread/**wacupbnlqgrfhaebdssd@forum.**
> dlang.org#post-**yhhtuojlsgiykyrfhngl:40forum.**dlang.org<http://forum.dlang.org/thread/wacupbnlqgrfhaebdssd@forum.dlang.org#post-yhhtuojlsgiykyrfhngl:40forum.dlang.org>
> )
>

I saw your other post. I'll try to understand what you're trying to do in the dpaste you posted.

I'm not sure I get your question, though. If a type is not known in the current scope, you cannot determine its number of arguments, because, well, it's not known.


December 17, 2012
On Saturday, 15 December 2012 at 21:49:51 UTC, Philippe Sigaud wrote:
>>
>> Oops ;/ How do I get the number of type arguments if I don't know them
>> yet? I know this sort of seems wrong but somehow, to know how to alias the
>> class I need to know it's number of arguments. (I don't think it makes too
>> much sense with the type system but not sure how to solve the following
>> problem without it:
>>
>> http://forum.dlang.org/thread/**wacupbnlqgrfhaebdssd@forum.**
>> dlang.org#post-**yhhtuojlsgiykyrfhngl:40forum.**dlang.org<http://forum.dlang.org/thread/wacupbnlqgrfhaebdssd@forum.dlang.org#post-yhhtuojlsgiykyrfhngl:40forum.dlang.org>
>> )
>>
>
> I saw your other post. I'll try to understand what you're trying to do in
> the dpaste you posted.
>
> I'm not sure I get your question, though. If a type is not known in the
> current scope, you cannot determine its number of arguments, because, well,
> it's not known.


I would like to be able to get the template args of a class inside the class:

class A(T1, T2)
{
   this() { pragma(msg, TemplateArgs!(typeof(this)).stringof); }
}

should print (T1, T2) or something similar.

When I run your code I get

tuple(true).

I'd also sort of like to setup an alias outside the class to refer to the class from inside without knowing the arguments explicitly

e.g.,


class A(T1, T2)
{
   this() { outer alias ... AB; } // ... is something like A!(T1, int) where T1 is inferred from being inside the class and int is explicit.
}

would be equivalent to something like

template A(T1,T2) { alias .A!(T1, int) A(T1); }

(this isn't suppose to be valid D code but pseudo-D code)

The idea is simply to reduce what the user outside the class has to know and type. If I were to parameterize a class:

class A(uT1, uT2, a,b,c,d,e,f,g,q,x,z,y) { }

and only uT1, uT2 were meant for the user and the rest were all statically known then I wouldn't want the user to have to type that stuff in... which is were aliases come in. Aliases don't seem to let you specify only a partial template list though, which, I think, is why you use templates?

But if I can create all the code inside the class that does this grunt work it would make it easier on the user and make it as transparent as possible. The goal is to make it feel like they are just using class A(uT1, uT2) rather than the other one. Since they are actually creating the class, the technique I use must work with any number of "user" template arguments.

In any case, being able to get the string name of a class, including the template arguments, would be very helpful in this.

Alternatively, having the ability to combine classes, even with different template arguments, would be useful(ah'la the other thread):

class Master(a,b,c,d,e,f,g,q,x,z,y) { xxx }
class User(uT1, uT2) { yyy }

Master(a,b,c,d,e,f,g,q,x,z,y) + User(uT1,uT2)
= struct MasterpUser(uT1,uT2,a,b,c,d,e,f,g,q,x,z,y) { xxx yyy }

which, if all of the master template arguments have default arguments then it should be easy to treat MasterpUser as if it were a User class and the user would not really know the difference between the two. (since MasterpUser contains all the functionality of User and the user does not know about the master's template args)

I, of course, provide the Master class, and the user(the programmer wanting the additional functionality, creates the User class.

It is very similar to inheritance except sort of static(no virtual functions, etc...). User, can, of course, also access data in Master(yyy could access Master's data) since they are actually the same class when combined.

It would be better to have a compile time inheritance construct as that is essentially what I'm trying to do:

class Master(a = 1,b = 2,c = 3,d = 4) { xxx }
class User(uT1, uT2) + Master!() { yyy [xxx is implicit] }

note that a class like

class User2(uT1, uT2) + Master!() { yyy [xxx is implicit] }

has no relationship to User(uT1, uT2) + Master!(). (well, it does but it at run time there is no common parent Master because there is no vtable. One could subtract the two classes to recover Master!() which would be non-empty and hence have overlap. This could only be carried out at compile time unless the functionality was added to the dynamic type system)

Anyways, I'm not sure if any of this is making sense but ultimately I'm trying to achieve something sort of like the above since I think D does not support such constructs. To do that, I need to be able to get the class name with it's type argument list without actually knowing them. typeof(this).stringof gets only the name... I need the other part.

I have seen someone mention a codeof trait, which is something I was also hoping for. This would make it easier to get what I want and also even implement an static algebra of classes and structs.










December 17, 2012
I see now why it was returning a bool as that is the type of the template argument passed.

class A(bool x = true)

then your TemplateArgs returns `tuple(bool)`. What I'm looking for is something that returns `(x)`. For class A(T1, T2, bool x = true) I would like `(T1, T2, x)`.

To see why this will help, in my Nested structs code, I have to do the following:

class _A(...., bool _NestedLevel = true) {
enum string __ClassNameFix = "_A!(....";
...}

Using what you said about typeof(this), I can now remove the class name dependency, so I have this:

enum string __ClassNameFix = __traits(identifier, typeof(this))~"!(....";

Now I want to remove the type argument list dependency(the `!(...` part).

Once that is done, I can completely remove the __ClassNameFix since I can get the class name and template arg names without user intervention. The whole point of __ClassNameFix was to provide a way for the user to specify the class name and args. I had to use strings so I could parse them. (since in my mixins I'll set _NestedLevel to false and such, using strings, which is easy)

If I could go the next step and get the template argument names it will drastically reduce the code in my template mixins.