Jump to page: 1 2
Thread overview
simple (I think) eponymous template question ... what is proper idimatic way ?
Aug 17, 2021
james.p.leblanc
Aug 17, 2021
Alexandru Ermicioi
Aug 17, 2021
H. S. Teoh
Aug 17, 2021
Ali Çehreli
Aug 17, 2021
james.p.leblanc
Aug 17, 2021
H. S. Teoh
Aug 17, 2021
james.p.leblanc
Aug 17, 2021
Paul Backus
Aug 17, 2021
james.p.leblanc
Aug 17, 2021
Bastiaan Veelo
Aug 17, 2021
Alexandru Ermicioi
Aug 18, 2021
james.p.leblanc
Aug 18, 2021
Tejas
Aug 18, 2021
james.p.leblanc
Aug 17, 2021
H. S. Teoh
August 17, 2021
Evening All,

Eponymous templates allow a nice calling syntax.  For example, "foo" here can
be called without needing the exclamation mark (!) at calling sites.  We see that
foo is restricting a, and b to be of the same type ... so far, so good.

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

Now, suppose I need to restrict "T" only certain subsets of variable types.

I can imagine putting in some "static if" statements in my function body,
is one solution.  (Also a bit ugly as the allowed types might grow).

Is there a more elegant way, to do this?

Regards,
James

PS Any violations should be caught at compile time.




August 17, 2021

On Tuesday, 17 August 2021 at 18:11:56 UTC, james.p.leblanc wrote:

>

Is there a more elegant way, to do this?

Regards,
James

PS Any violations should be caught at compile time.

That is template specialization:

auto moo(T : YourSpecialClassOrDType)(T myMoo) {•••}

You can also declare other overloads of the method, just make sure they don't overlap in the constraints, otherwise you'd get ambiguous call exception.

Regards,
Alexandru.

August 17, 2021
On Tue, Aug 17, 2021 at 06:11:56PM +0000, james.p.leblanc via Digitalmars-d-learn wrote:
> Evening All,
> 
> Eponymous templates allow a nice calling syntax.  For example, "foo" here can be called without needing the exclamation mark (!) at calling sites.  We see that foo is restricting a, and b to be of the same type ... so far, so good.
> 
> auto foo(T)(T a, T b) { ... }
> 
> Now, suppose I need to restrict "T" only certain subsets of variable types.

This is exactly what "signature constraints" are for.  For example:

	auto foo(T)(T a, T b)
	if (is(T == string)) // <--- this is a signature constraint
	{
		... // deal with strings here
	}

	auto foo(T)(T a, T b)
	if (is(T == int)) // you can overload on signature constraints
	{
		... // deal with ints here
	}

	auto foo(T)(T a, T b)
	if (is(T == float) || is(T == double)) // you can use complex conditions
	{
		... // deal with floats or doubles here
	}

Be aware that a signature constraint failure is not an error: the compiler simply skips that overload of the function.  So if you make a mistake in a sig constraint, it may *always* fail, and the compiler may try instead to instantiate a completely unintended overload and generate an error that may have nothing to do with the actual problem.


T

-- 
Give a man a fish, and he eats once. Teach a man to fish, and he will sit forever.
August 17, 2021
On 8/17/21 11:11 AM, james.p.leblanc wrote:

> auto foo(T)(T a, T b) { ... }
>
> Now, suppose I need to restrict "T" only certain subsets of variable types.

There are template constraints:

import std.traits;

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

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

void main() {
  foo(1.5, 2.5);
}

See __traits as well and of course you can use any compile-time check in the template constraint.

> I can imagine putting in some "static if" statements in my function body,

That method can display an intelligible error message if there is only one template implementation. Template constraints on the other hand, are not errors; they just determine what template implementations are available for instantiation for the used parameters.

And of course, 'static if' has more uses other than just error reporting; which might be performed better with 'static assert'.

Ali

August 17, 2021

On 8/17/21 2:11 PM, james.p.leblanc wrote:

>

Evening All,

Eponymous templates allow a nice calling syntax.  For example, "foo" here can
be called without needing the exclamation mark (!) at calling sites.  We see that
foo is restricting a, and b to be of the same type ... so far, so good.

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

Now, suppose I need to restrict "T" only certain subsets of variable types.

I can imagine putting in some "static if" statements in my function body,
is one solution.  (Also a bit ugly as the allowed types might grow).

Is there a more elegant way, to do this?

Template constraints.

-Steve

August 17, 2021

On Tuesday, 17 August 2021 at 18:28:53 UTC, Steven Schveighoffer wrote:

>

On 8/17/21 2:11 PM, james.p.leblanc wrote:

>

Evening All,

Template constraints.

-Steve

Dear All,

Thanks! I was aware of, and have used template constraints in simple ways.

But, I should express my question a bit better:
"... is there a more elegant way to expression these constraints?"

Perhaps by extending Alexandru's "moo" concepts, with a list of allowed types:

auto moo(T : (int || float || mySpecialStruct )(T myMoo) {•••}

When re-using any such sets, it would be nice to define the set as follows:

S = (int || float || mySpecialStruct)

and then define "moo" more concisely as:

auto moo(T < S)(T myMoo) {•••}

( where I have used "<" to mean "T is a member of S").

Possible?

Best Regards,
James

August 17, 2021
On Tue, Aug 17, 2021 at 07:22:54PM +0000, james.p.leblanc via Digitalmars-d-learn wrote: [...]
> auto moo(T : (int || float || mySpecialStruct )(T myMoo) {•••}
> 
> When re-using any such sets, it would be nice to define the set as follows:
> 
> S = (int || float || mySpecialStruct)
> 
> and then define "moo" more concisely as:
> 
> auto moo(T < S)(T myMoo) {•••}
> 
> ( where I have used "<" to mean "T is a member of S").
[...]

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)) { ... }


T

-- 
I am a consultant. My job is to make your job redundant. -- Mr Tom
August 17, 2021
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)) { ... }
>
>
> T

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.

Best Regards,
James



August 17, 2021
On Tuesday, 17 August 2021 at 19:53:52 UTC, james.p.leblanc 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)) { ... }
>>
>>
>> T
>
> 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.
>
> Best Regards,
> James

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
August 17, 2021
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.
« First   ‹ Prev
1 2