August 17, 2021
On Tuesday, 17 August 2021 at 20:13:59 UTC, Paul Backus wrote:

> FYI: in this particular case, you can use std.meta.staticIndexOf instead of writing the recursion out yourself:
>
>     import std.meta: staticIndexOf;
>     enum isAmong(T, S...) = staticIndexOf!(T, S) >= 0;
>
> Docs: https://phobos.dpldocs.info/std.meta.staticIndexOf.html

All,  Thanks again ... Paul, I will try this staticIndexOf as you mention.

I had been receiving "circular reference to variable" error messages from the
"isAmong" suggestion.  (But, I very likely had  misunderstood how to use this.)

I would still be interested to learn what I have done wrong.  So, below
is my code:

import std.stdio;
import std.meta : AliasSeq;

template isAmong(T, S...) {
   static if (S.length == 0)
      enum isAmong = false;
   else
      enum isAmong = is(T == S) || isAmong(T, S[1..$]);
}

alias MyTypes = AliasSeq!(int, float);

auto myFunc(T)(T a, T b) if (isAmong!(T, MyTypes)) {
  writeln(" in myFunc ");
  return;
}

void main(){
  writeln("started ...");
   auto a = 1;
   auto b = 2;
   myFunc!(int)(a, b);
   return;
}


And, here are the error message:

(master) Notes > dmd recursive_template.d
recursive_template.d(9): Error: circular reference to variable `recursive_template.isAmong!(int, int, float).isAmong`
recursive_template.d(17): Error: template instance `recursive_template.isAmong!(int, int, float)` error instantiating
recursive_template.d(29):        while looking for match for `myFunc!int`

Can anyone see what is going on?

Best Regards,
James



August 17, 2021
On Tue, Aug 17, 2021 at 07:53:52PM +0000, james.p.leblanc via Digitalmars-d-learn wrote:
> On Tuesday, 17 August 2021 at 19:44:29 UTC, H. S. Teoh wrote:
> > You could use a helper template and an AliasSeq for this:
> > 
> > 	template isAmong(T, S...) {
> > 		static if (S.length == 0)
> > 			enum isAmong = false;
> > 		else
> > 			enum isAmong = is(T == S) ||
> > 				isAmong(T, S[1..$]);
> > 	}
> > 
> > 	import std.meta : AliasSeq;
> > 	alias MyTypes = AliasSeq!(int, float, MySpecialStruct);
> > 
> > 	auto myFunc(T)(T a, T b) if (isAmong!(T, MyTypes)) { ... }
[...]
> Dear H.S. Teoh,
> 
> Wow!  That is absolutely beautiful ... I had never seen (or even imagined) a recursive template!  This expands my mind in a good way ... and is going into my toolbox immediately.
[...]

I didn't want to spoil your joy of discovery, but since others have already done that -- beware of recursive templates, because if used too often they can become a source of big slowdowns to your compilation times (as well as the compiler consuming ridiculous amounts of memory).

Simple, linearly-recursive templates like this one are probably harmless (unless you artificially generate pathologically-long lists of types). But if the recursion gets too deep or grows superlinearly, you probably want to consider alternative implementations instead. ;-)


--T
August 17, 2021

On Tuesday, 17 August 2021 at 20:29:51 UTC, james.p.leblanc wrote:

>

So, below
is my code:

import std.stdio;
import std.meta : AliasSeq;

template isAmong(T, S...) {
static if (S.length == 0)
enum isAmong = false;
else
enum isAmong = is(T == S) || isAmong(T, S[1..$]);
}

alias MyTypes = AliasSeq!(int, float);

auto myFunc(T)(T a, T b) if (isAmong!(T, MyTypes)) {
writeln(" in myFunc ");
return;
}

void main(){
writeln("started ...");
auto a = 1;
auto b = 2;
myFunc!(int)(a, b);
return;
}

And, here are the error message:

(master) Notes > dmd recursive_template.d
recursive_template.d(9): Error: circular reference to variable recursive_template.isAmong!(int, int, float).isAmong
recursive_template.d(17): Error: template instance recursive_template.isAmong!(int, int, float) error instantiating
recursive_template.d(29): while looking for match for myFunc!int

Can anyone see what is going on?

Best Regards,
James

https://run.dlang.io/is/m5svQ2

The error was in line 8.
T (Teoh) forgot to take the first of S in is(T == S[0]). The error message improves after adding the ! in isAmong!(T, S[1..$]), which, surprisingly, is optional!

— Bastiaan.

August 18, 2021

On Tuesday, 17 August 2021 at 20:28:20 UTC, Alexandru Ermicioi wrote:

>

On Tuesday, 17 August 2021 at 19:53:52 UTC, james.p.leblanc wrote:

>

Wow! That is absolutely beautiful ... I had never seen (or even
imagined) a recursive template! This expands my mind in a good
way ... and is going into my toolbox immediately.

Best Regards,
James

Just don't over rely on it. It can cause compilation slowdowns, so avoid it if you can.

I've been happily trying to absorb all the helpful concepts posted.

A final related question in the quest for simplicity and robustness.

If I wanted to ensure that a function accepts only arguments of
byte, int, uint, long, etc. (i.e. integer-like types). Is the accepted
way to do this like so?:

auto foo( T : long )(T a, T b){ ... }

I really wish I could find a good explanation of the ":" (colon)
used in templates. I am sure one exists ...but haven't come upon
it just yet.

(I thought "isIntegral" in traits module would be helpful...but
I failed in my experiments.)

Thanks for patience with this question!

Best Regards,
James

August 18, 2021

On Wednesday, 18 August 2021 at 05:33:13 UTC, james.p.leblanc wrote:

>

If I wanted to ensure that a function accepts only arguments of
byte, int, uint, long, etc. (i.e. integer-like types). Is the accepted way to do this like so?:

auto foo( T : long )(T a, T b){ ... }

I very much prefer the ususal constraint syntax

auto foo(T)(T a, T b) if(isIntegral!T) { ... }

August 18, 2021

On Wednesday, 18 August 2021 at 05:33:13 UTC, james.p.leblanc wrote:

>

On Tuesday, 17 August 2021 at 20:28:20 UTC, Alexandru Ermicioi wrote:

>

On Tuesday, 17 August 2021 at 19:53:52 UTC, james.p.leblanc wrote:

>

Wow! That is absolutely beautiful ... I had never seen (or even
imagined) a recursive template! This expands my mind in a good
way ... and is going into my toolbox immediately.

Best Regards,
James

Just don't over rely on it. It can cause compilation slowdowns, so avoid it if you can.

I've been happily trying to absorb all the helpful concepts posted.

A final related question in the quest for simplicity and robustness.

If I wanted to ensure that a function accepts only arguments of
byte, int, uint, long, etc. (i.e. integer-like types). Is the accepted
way to do this like so?:

auto foo( T : long )(T a, T b){ ... }

I really wish I could find a good explanation of the ":" (colon)
used in templates. I am sure one exists ...but haven't come upon
it just yet.

(I thought "isIntegral" in traits module would be helpful...but
I failed in my experiments.)

Thanks for patience with this question!

Best Regards,
James

A template specialization is basically a template overload.

For example:


void func(int a){
      writeln("argument is integer");
}

void func(long a){
      writeln("argument is long");
}

void main(){
     int a;
     long b;
     func(a);
     func(b);
}

The above does what you expect.

Now the template specialization way:


void funcTemplate(T:int)(T a){
     writeln("argument is int");
}

void funcTemplate(T : long)(T a){
     writeln("argument is long");
}

void main(){
     int c;
     long d;
     funcTemplate(c);
     funcTemplate(d);
}

The above will also do what you expect.

Template specialization is basically overloading for templates, nothing more.

Below is a complete working copy-paste example combining both:


import std;



void func(int a){
      writeln("argument is integer");
}

void func(long a){
      writeln("argument is long");
}



void funcTemplate(T:int)(T a){
     writeln("argument is int");
}

void funcTemplate(T : long)(T a){
     writeln("argument is long integer");
}

void main(){
     int a;
     long b;
     func(a);
     func(b);

     funcTemplate(a);
     funcTemplate(b);

}

August 18, 2021

On Wednesday, 18 August 2021 at 06:53:51 UTC, Tejas wrote:

>

void funcTemplate(T:int)(T a){
writeln("argument is int");
}

void funcTemplate(T : long)(T a){
writeln("argument is long integer");
}

void main(){
int a;
long b;
func(a);
func(b);

 funcTemplate(a);
 funcTemplate(b);

}

Domninikus, Tejas, and All,

I see that I had been (stupidly) omitting the exclamation point
after "isIntegral" in my clumsy attempts to use the traits ...
thanks for your clear example helping me identify my error.

Also, thanks for mentioning the words "template specialization" , I did
not know what to call the use of ":" in templates.

Now, I have a search term I can use to learn more ...and find it is in Phillippe
Signaud's informative "D-templates-tutorial".

Thanks again,
James

PS Also, I am enjoying, a entertaining and educational tutorial that Phillippe
has linked in his tutorial. Other may learn from this as well:

http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/

1 2
Next ›   Last »