Thread overview
How to stringify a template instantiation expression?
Feb 28, 2018
Yuxuan Shui
Feb 28, 2018
aliak
Mar 01, 2018
Yuxuan Shui
Mar 01, 2018
Yuxuan Shui
Mar 01, 2018
Simen Kjærås
Mar 02, 2018
Yuxuan Shui
Mar 01, 2018
aliak
February 28, 2018
For a template instantiation expression like A!(B, C!(D, E)), I want to get a string "A!(B, C!(D, E))", better if A, B, C, D, E is replaced by fully qualified name.

Is this possible?
February 28, 2018
On Wednesday, 28 February 2018 at 15:09:56 UTC, Yuxuan Shui wrote:
> For a template instantiation expression like A!(B, C!(D, E)), I want to get a string "A!(B, C!(D, E))", better if A, B, C, D, E is replaced by fully qualified name.
>
> Is this possible?

A!(B, C!(D, E)).stringof I guess. Will print the former.

There's a Learn forum as well btw :)

Cheers
March 01, 2018
On Wednesday, 28 February 2018 at 15:49:25 UTC, aliak wrote:
> On Wednesday, 28 February 2018 at 15:09:56 UTC, Yuxuan Shui wrote:
>> For a template instantiation expression like A!(B, C!(D, E)), I want to get a string "A!(B, C!(D, E))", better if A, B, C, D, E is replaced by fully qualified name.
>>
>> Is this possible?
>
> A!(B, C!(D, E)).stringof I guess. Will print the former.
>
> There's a Learn forum as well btw :)
>
> Cheers

Did you actually try that? With dmd 2.079-rc1, this:

template A(T...) {}
struct B {}
struct D {}
struct E {}
template C(T...) {}
pragma(msg, (A!(B, C!(D, E))).stringof);

Prints:

A!(B, __T1CTS2ax1DTSQh1EZ)

When compiled
March 01, 2018
On Thursday, 1 March 2018 at 16:46:30 UTC, Yuxuan Shui wrote:
> On Wednesday, 28 February 2018 at 15:49:25 UTC, aliak wrote:
>> On Wednesday, 28 February 2018 at 15:09:56 UTC, Yuxuan Shui wrote:
>>> For a template instantiation expression like A!(B, C!(D, E)), I want to get a string "A!(B, C!(D, E))", better if A, B, C, D, E is replaced by fully qualified name.
>>>
>>> Is this possible?
>>
>> A!(B, C!(D, E)).stringof I guess. Will print the former.
>>
>> There's a Learn forum as well btw :)
>>
>> Cheers
>
> Did you actually try that? With dmd 2.079-rc1, this:
>
> template A(T...) {}
> struct B {}
> struct D {}
> struct E {}
> template C(T...) {}
> pragma(msg, (A!(B, C!(D, E))).stringof);
>
> Prints:
>
> A!(B, __T1CTS2ax1DTSQh1EZ)
>
> When compiled

Even worse, if the template instantiation yields another template, e.g:

template A(T) { template A(T) {} }

A!int.stringof returns "A(T)", which is not useful at all.
March 01, 2018
On Thursday, 1 March 2018 at 16:46:30 UTC, Yuxuan Shui wrote:
> On Wednesday, 28 February 2018 at 15:49:25 UTC, aliak wrote:
>> On Wednesday, 28 February 2018 at 15:09:56 UTC, Yuxuan Shui wrote:
>>> For a template instantiation expression like A!(B, C!(D, E)), I want to get a string "A!(B, C!(D, E))", better if A, B, C, D, E is replaced by fully qualified name.
>>>
>>> Is this possible?
>>
>> A!(B, C!(D, E)).stringof I guess. Will print the former.
>>
>> There's a Learn forum as well btw :)
>>
>> Cheers
>
> Did you actually try that? With dmd 2.079-rc1, this:
>
> template A(T...) {}
> struct B {}
> struct D {}
> struct E {}
> template C(T...) {}
> pragma(msg, (A!(B, C!(D, E))).stringof);
>
> Prints:
>
> A!(B, __T1CTS2ax1DTSQh1EZ)
>
> When compiled

string TemplateStringOf(T...)()
if (T.length == 1)
{
    import std.traits : TemplateOf, TemplateArgsOf;
    import std.meta : AliasSeq, staticMap;
    import std.string : indexOf;
    import std.conv : text;
    static if (is(typeof({ alias a = TemplateOf!T; })))
    {
        alias Tmp = TemplateOf!T;
        alias Args = TemplateArgsOf!T;

        enum tmpFullName = Tmp.stringof;
        enum tmpName = tmpFullName[0..tmpFullName.indexOf('(')];

        alias AddCommas(T...) = AliasSeq!(T, ", ");
        alias ArgNames = staticMap!(.TemplateStringOf, Args);
        alias SeparatedArgNames = staticMap!(AddCommas, ArgNames)[0..$-1];

        return text(tmpName, "!(", SeparatedArgNames, ")");
    }
    else
    {
        return T[0].stringof;
    }
}

unittest {
    template A(T...) {}
    struct B {}
    struct D {}
    struct E {}
    template C(T...) {}

    assert(TemplateStringOf!(A!(B, C!(D, E))) == "A!(B, C!(D, E))");
}

unittest {
    template A(T) { template A(T) {} }

    assert(TemplateStringOf!(A!int) == "A!(int)");
}

Probably still some corner cases I haven't thought of, but it seems to cover what you're asking for.

One thing I didn't bother with is disambiguation - if B exists in modules foo and bar, the above will not specify which foo it's referring to. This is left as an exercise for the reader.

--
  Simen
March 01, 2018
On Thursday, 1 March 2018 at 16:46:30 UTC, Yuxuan Shui wrote:
> Did you actually try that? With dmd 2.079-rc1, this:
>
> template A(T...) {}
> struct B {}
> struct D {}
> struct E {}
> template C(T...) {}
> pragma(msg, (A!(B, C!(D, E))).stringof);
>
> Prints:
>
> A!(B, __T1CTS2ax1DTSQh1EZ)
>
> When compiled

Yep, though not all possible combinations of course:

struct X(T...) {}

void main() {
    writeln(X!(int, X!(X!(int), float), char).stringof);
}

Seems like if you throw in template templates then things get a little more ... complicated.
March 02, 2018
On Thursday, 1 March 2018 at 17:48:02 UTC, Simen Kjærås wrote:
> On Thursday, 1 March 2018 at 16:46:30 UTC, Yuxuan Shui wrote:
>> [...]
>
> string TemplateStringOf(T...)()
> if (T.length == 1)
> {
>     import std.traits : TemplateOf, TemplateArgsOf;
>     import std.meta : AliasSeq, staticMap;
>     import std.string : indexOf;
>     import std.conv : text;
>     static if (is(typeof({ alias a = TemplateOf!T; })))
>     {
>         alias Tmp = TemplateOf!T;
>         alias Args = TemplateArgsOf!T;
>
> [...]

Ah, thanks. I was trying to match template instantiation using is() (i.e. is(T == S!R, S, R...)). But this doesn't work if T is a template.

Reading the code of TemplateOf, I realized I have to use template constraints for that. Maybe we can add support for something like is(alias T == ...)?