www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D's limited template specialization abilities compared to C++

reply "Ahuzhgairl" <bulletproofchest gmail.com> writes:
Hi,

In D, the : in a template parameter list only binds to 1 
parameter.
There is no way to specialize upon the entire template parameter 
list.
Therefore you can't do much with the pattern matching and it's 
not powerful.
Not a reasonable situation for a language aiming to be only the 
best.

What is needed is the ability to bind to the whole template 
parameter list:

template <class> struct get_class;
template <class R, class C, class... A> struct get_class<R 
(C::*)(A...)> { typedef C type; };

Let's shorten the terms:

<R, C, A...>   <R (C::*)(A...)>

And here's how this kind of specialization would work in D:

template A[B] { struct C {} } template Foo[alias X, Y, Z   
X[Y].Z] { alias Z Foo; } void main() { alias Foo[A[bool].C] xxx; }

You need a separate delimiter besides : which does not bind to 
individual parameters, but which binds to the set of parameters.

I propose   as the character which shall be the delimiter for the 
arguments to the pattern match, and the pattern match.

On an unrelated note, I don't like the ! thing so I use []. Sorry 
for the confusion there.

z
May 25 2013
next sibling parent "Ahuzhgairl" <bulletproofchest gmail.com> writes:
By extension,

template Foo[X, Y, Z   X[Y], Y[Z]] { alias Y Foo; }
May 25 2013
prev sibling next sibling parent reply "Peter Alexander" <peter.alexander.au gmail.com> writes:
Is this what you're looking for?

struct Foo(T)
{
	static void bar() { writeln("general"); }
}

struct Foo(T : A[B], A, B)
{
	static void bar() { writeln("special"); }
}

void main()
{
	Foo!(int).bar(); // general
	Foo!(int[int]).bar(); // special
}
May 25 2013
parent reply "Ahuzhgairl" <bulletproofchest gmail.com> writes:
No,




struct Foo(T) {
     static void f() { writeln("general"); }
}

struct Foo(T : A(B).alias C, A, B, C) {
     static void f() { writeln("special"); }
}

struct Bar(T) {
     struct Baz {}
}

struct Baz(T : A(B), A, B) {
}

void main() {
     Foo!(Bar!(int).Baz);
     Baz!(Bar!(int));
}
May 25 2013
next sibling parent reply "Ahuzhgairl" <bulletproofchest gmail.com> writes:
Uneditable newsgroups. Simplest case.

struct Bar(T) {}

struct Foo(T : A(B), A, B) {
     static void f() {}
}

void main() {
     Foo!(Bar!(int)).f();
}
May 25 2013
next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Saturday, 25 May 2013 at 12:13:42 UTC, Ahuzhgairl wrote:
 Uneditable newsgroups. Simplest case.

 struct Bar(T) {}

 struct Foo(T : A(B), A, B) {
     static void f() {}
 }

 void main() {
     Foo!(Bar!(int)).f();
 }
Two problems with that: 1. A(B) should be A!(B) 2. A won't bind to Bar because Bar is not a type, it is a template. A should be an alias. This works: struct Bar(T) {} struct Foo(T : A!(B), alias A, B) { static void f() {} } void main() { Foo!(Bar!(int)).f(); }
May 25 2013
prev sibling next sibling parent Kenji Hara <k.hara.pg gmail.com> writes:
2013/5/25 Ahuzhgairl <bulletproofchest gmail.com>

 Uneditable newsgroups. Simplest case.

 struct Bar(T) {}

 struct Foo(T : A(B), A, B) {
     static void f() {}
 }

 void main() {
     Foo!(Bar!(int)).f();
 }
It would work. struct Bar(T) {} struct Foo(T : A!(B), alias A, B) { // 1, 2 static void f() {} } void main() { Foo!(Bar!(int)).f(); } 1. should use A!(B), instead of A(B) 2. A would match to template, so should receive by TemplateAliasParameter. Kenji Hara
May 25 2013
prev sibling parent reply "Ahuzhgairl" <bulletproofchest gmail.com> writes:
C++ example, works:

template <class> struct A;
template <template <class> class X, class Y> struct A<X<Y>> {};

template <class> struct B;

int main() {
     A<B<int>> a;
}



But the following does not work:

struct Foo {};
template <class> struct B { Foo x; }

template <nontype P> struct A;
template <auto M, auto C, nontype P> struct A<M C::*P> {}

int main() {
     A<&B<int>::x> a;
}


D should be able to do both.
May 25 2013
parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Saturday, 25 May 2013 at 12:43:42 UTC, Ahuzhgairl wrote:
 C++ example, works:

 template <class> struct A;
 template <template <class> class X, class Y> struct A<X<Y>> {};

 template <class> struct B;

 int main() {
     A<B<int>> a;
 }
As we've shown, you can do this in D. Instead of template templates, you use alias.
 But the following does not work:

 struct Foo {};
 template <class> struct B { Foo x; }

 template <nontype P> struct A;
 template <auto M, auto C, nontype P> struct A<M C::*P> {}

 int main() {
     A<&B<int>::x> a;
 }
It's getting very hard to see what you're trying to do. I think it would help if you used real C++ and D syntax instead of inventing new syntax because I can't tell what you're trying to achieve and what semantics you expect of it. Please post a small example of real, working, compilable C++ that shows what you want to do, and we'll show you how to do it in D (assuming it is possible).
May 25 2013
prev sibling parent reply Kenji Hara <k.hara.pg gmail.com> writes:
2013/5/25 Ahuzhgairl <bulletproofchest gmail.com>

 No,

 struct Foo(T) {
     static void f() { writeln("general"); }
 }

 struct Foo(T : A(B).alias C, A, B, C) {
     static void f() { writeln("special"); }
 }

 struct Bar(T) {
     struct Baz {}
 }

 struct Baz(T : A(B), A, B) {
 }

 void main() {
     Foo!(Bar!(int).Baz);
     Baz!(Bar!(int));
 }
As I already shown, Baz!(Bar!(int)); could work in D. But, currently Foo!(Bar!(int).Baz); is not yet supported. I'm opening a compiler enhancement for related case, http://d.puremagic.com/issues/show_bug.cgi?id=9022 and right now I updated compiler patch to allow parameterize enclosed type by name/type/alias. https://github.com/D-Programming-Language/dmd/pull/1296 https://github.com/9rnsr/dmd/commit/b29726d30b0094b9e7c2e15f5802501cb686ee68 After it is merged, you can write it as follows. import std.stdio; struct Foo(T) { static void f() { writeln("general"); } } struct Foo(T : A!(B).C, alias A, B, alias C) { static void f() { writeln("special"); } } struct Bar(T) { struct Baz {} } void main() { Foo!(Bar!(int).Baz) x; x.f(); // prints "special" } Kenji Hara
May 25 2013
parent reply "Ahuzhgairl" <bulletproofchest gmail.com> writes:
Kenji,
Thank you much for the '.C' alias support, Amazed to see there 
could be some action so quick!


Could we please look at the nontype-as-primary-template?

How can we deduce all of the dependent types from a non-type 
template parameter, if it's the only parameter of the primary 
template?



struct Foo {};
template <class> struct B { Foo x; }

template <nontype P> struct A;
// P is the primary-template param

template <auto M, auto C, nontype P> struct A<M C::*P> {
     // Given the call in main,
     // M is deduced as Foo
     // C is deduced as B<int>
     // P was passed successfully and we know the types that make 
it up.
}

int main() {
     auto mp = &B<B<int>>::x
     A<mp> a;
}
May 25 2013
next sibling parent reply Kenji Hara <k.hara.pg gmail.com> writes:
2013/5/26 Ahuzhgairl <bulletproofchest gmail.com>

 Kenji,
 Thank you much for the '.C' alias support, Amazed to see there could be
 some action so quick!


 Could we please look at the nontype-as-primary-template?

 How can we deduce all of the dependent types from a non-type template
 parameter, if it's the only parameter of the primary template?




 struct Foo {};
 template <class> struct B { Foo x; }

 template <nontype P> struct A;
 // P is the primary-template param


 template <auto M, auto C, nontype P> struct A<M C::*P> {
     // Given the call in main,
     // M is deduced as Foo
     // C is deduced as B<int>
     // P was passed successfully and we know the types that make it up.
 }

 int main() {
     auto mp = &B<B<int>>::x
     A<mp> a;
 }
Hmm. Currently D can specify specType for alias template parameter. struct X(alias int x) {} // matches only when the symbol x has the type int void main() { int a; X!a xa; // match OK long b; X!b xb; // match NG } But, compiler does not allow parameterize of specType. struct Foo {} struct B(T) { static Foo x; } //struct A(alias P) {} struct A(alias M* P, M) // matches only when the symbol P has the type M* //struct A(alias C.M* P, M, C) { } void main() { auto mp = &B!(B!int).x; A!mp a; // does not match... } I think it should be allowed. Kenji Hara
May 25 2013
parent reply "Ahuzhgairl" <bulletproofchest gmail.com> writes:
Kenji, thanks again for understanding exactly what I meant.

I am a big fan of template features. I seriously hope D can do 
this in the future- the inability of the *template system* to 
deduce information about non-types is one of the big holes in C++:

We can deduce information at function scope, yet the templates 
cannot do it!
This is a strange imbalance of nature.
May 25 2013
parent Manu <turkeyman gmail.com> writes:
On 26 May 2013 16:41, Ahuzhgairl <bulletproofchest gmail.com> wrote:

 Kenji, thanks again for understanding exactly what I meant.

 I am a big fan of template features. I seriously hope D can do this in the
 future- the inability of the *template system* to deduce information about
 non-types is one of the big holes in C++:

 We can deduce information at function scope, yet the templates cannot do
 it!
 This is a strange imbalance of nature.
I presume this is Ndit from IRC? The part that breaks my mind, is that you appeared professing you were missing requirements for realtime critical software (and significantly more realtime critical than my own work apparently), but then you became the most obscure template crazed dude I've ever seen. In my experience, the 2 are fundamentally incompatible. A realtime programmer with requirements as strict as you claim, would avoid intensive (ab)use of templates like the plague! :/ It really seems like you're just trying to break D in whichever way you can (and having some trouble). And now in 3 cases, where you have successfully 'broken' D, a helpful member from the community has taken it upon themselves to help you and give you what you want. Have you actually tried working with D templates for a while. Templates are, hands down, the strongest and most compelling feature of D. If you actually use D for a short time, you will realise this. Now, I tend to think the level of support shown to you is spectacular, taking entire days of peoples time. Especially considering you've never managed to produce an actual use cased for anything you've come up with. But I'd like to make a suggestion that you actually USE D for a while, and waste peoples time with REAL USE CASES where you find that your needs are not satisfied. D is a volunteer community, if you never plan to use these improvements, and nobody else ever does, then you're effectively wasting their time, which is a little unfair.
May 26 2013
prev sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 5/26/13, Kenji Hara <k.hara.pg gmail.com> wrote:
 Hmm. Currently D can specify specType for alias template parameter.

 struct X(alias int x) {}   // matches only when the symbol x has the type int
This feature is news to me! Pretty cool. Philippe Sigaud: Is this mentioned in the D Template book?
May 26 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 05/26/2013 03:04 PM, Andrej Mitrovic wrote:
 On 5/26/13, Kenji Hara <k.hara.pg gmail.com> wrote:
 Hmm. Currently D can specify specType for alias template parameter.

 struct X(alias int x) {}   // matches only when the symbol x has the type int
This feature is news to me! Pretty cool.
I'm about 3/4 through a D frontend implementation and was unaware of this. :) The reason is that the feature is undocumented. (The grammar specification mentions the syntax, though.)
  Philippe Sigaud: Is this mentioned in the D Template book?
I don't think so.
May 26 2013
parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 5/27/13, Timon Gehr <timon.gehr gmx.ch> wrote:
 The reason is that the feature is undocumented. (The grammar
 specification mentions the syntax, though.)
I wonder how many other easter eggs there are in the language. :p
May 27 2013
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 25 May 2013 at 10:46:05 UTC, Ahuzhgairl wrote:
 Hi,

 In D, the : in a template parameter list only binds to 1 
 parameter.
 There is no way to specialize upon the entire template 
 parameter list.
 Therefore you can't do much with the pattern matching and it's 
 not powerful.
 Not a reasonable situation for a language aiming to be only the 
 best.

 What is needed is the ability to bind to the whole template 
 parameter list:

 template <class> struct get_class;
 template <class R, class C, class... A> struct get_class<R 
 (C::*)(A...)> { typedef C type; };

 Let's shorten the terms:

 <R, C, A...>   <R (C::*)(A...)>

 And here's how this kind of specialization would work in D:

 template A[B] { struct C {} } template Foo[alias X, Y, Z   
 X[Y].Z] { alias Z Foo; } void main() { alias Foo[A[bool].C] 
 xxx; }

 You need a separate delimiter besides : which does not bind to 
 individual parameters, but which binds to the set of parameters.

 I propose   as the character which shall be the delimiter for 
 the arguments to the pattern match, and the pattern match.

 On an unrelated note, I don't like the ! thing so I use []. 
 Sorry for the confusion there.

 z
Hi, I obviously don't know D that much, but I assume I do. I have this feature that I can't even show a working example that exists in C++. I also can't come up with any use case, but I know this is mandatory to have. As I assume I know D well enough, I assume I know that this is impossible in D, so I propose an improvement. With that improvement, a new syntax is introduced to support some new feature that is barely defined and it can be used in unknown situation. I also explain myself using my own made up syntax. I don't care if it conflict with other language construct as it is superior anyway.
May 25 2013
next sibling parent "Joshua Niehus" <jm.niehus gmail.com> writes:
On Saturday, 25 May 2013 at 16:27:59 UTC, deadalnix wrote:
 Hi, I obviously don't know D that much, but I assume I do.
 [..snip..]
<chuckle> +1
May 25 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/25/13 12:27 PM, deadalnix wrote:
 Hi, I obviously don't know D that much, but I assume I do.

 I have this feature that I can't even show a working example that exists
 in C++. I also can't come up with any use case, but I know this is
 mandatory to have.

 As I assume I know D well enough, I assume I know that this is
 impossible in D, so I propose an improvement.

 With that improvement, a new syntax is introduced to support some new
 feature that is barely defined and it can be used in unknown situation.

 I also explain myself using my own made up syntax. I don't care if it
 conflict with other language construct as it is superior anyway.
A great thing about this community is it being nice and helpful to newcomers. (That said, I had a good chuckle - I've seen this pattern before.) To the OP: you may want to look into template constraints, they're much easier to define and use than pattern matching in template arguments. Also, aliases are quite a bit more convenient and general than C++'s template template arguments, which run completely amok at the third regression: template<template<template <class> class> class T> class C; Andrei
May 25 2013