www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Can you tell if an template alias parameter is of a specific template?

reply aliak <something something.com> writes:
Hi

Is there a way to tell if an alias is to a template?

I'm writing some algorithms and I need to distinguish between a 
binary predicate that provides "less than" and one that provides 
"equal to" semantics. So I have these two templates:

template eq(alias pred) {
     alias eq = pred;
}

template lt(alias pred) {
     alias lt = pred;
}

Then in some place:

static if (is(pred == eq)) {
   return eq(a, b);
} else static if (is(pred == lt)) {
   return !lt(a, b) && !lt(b, a); // equality with less than 
predicate
} else {
   // default assumptions about predicate
}

Then I can use it like:

auto a = S!(eq!((a, b) => a == b)) ;
auto a = S!(lt!((a, b) => a < b));

I've tried std.traits.TemplateOf and __traits(isSame and also 
variations of typeof and also traits.isInstanceOf. I wonder if I 
have to parameterize eq and lt over a compile time sequence 
instead?

Any tips to get this working?

Cheers,
- Ali
Aug 03 2018
next sibling parent reply Hakan Aras <hakan.aras live.at> writes:
I don't think you can distinguish between entities evaluated 
through different templates. TemplateOf will paradoxically not 
work on pure templates of the form "template X() {}" only things 
like template functions and template structs. isSame, is, and 
isInstanceOf will only work on the fully evaluated type or alias 
(pred) not the template that was used to evaluate it.

If I understood your usecase correctly, you could do something 
like this though:

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

That is use an enum as a template parameter instead of wrapping 
the predicate in a template.
Aug 03 2018
parent aliak <something something.com> writes:
On Friday, 3 August 2018 at 19:10:45 UTC, Hakan Aras wrote:
 I don't think you can distinguish between entities evaluated 
 through different templates. TemplateOf will paradoxically not 
 work on pure templates of the form "template X() {}" only 
 things like template functions and template structs. isSame, 
 is, and isInstanceOf will only work on the fully evaluated type 
 or alias (pred) not the template that was used to evaluate it.

 If I understood your usecase correctly, you could do something 
 like this though:

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

 That is use an enum as a template parameter instead of wrapping 
 the predicate in a template.
You did understand and yep that'd work as well! I was not too happy about the extra parameter though and it'd be nice to have the information in the type. But I think I figured it out: struct eq(alias _pred) { alias pred = _pred; } struct lt(alias _pred) { alias pred = _pred; } void main() { import std.stdio: writeln; static struct S(alias pred) { auto f(int a, int b) { static if (is(pred : eq!p, p...)) { return p[0](a, b); } else static if (is(pred : lt!p, p...)) { return !p[0](a, b) && !p[0](b, a); } else { import std.functional: binaryFun; return binaryFun!pred(a, b); } } } alias a = eq!((a, b) => a == b); alias b = lt!((a, b) => a < b); S!(a)().f(1, 1).writeln; S!(b)().f(1, 1).writeln; S!"a == b"().f(1, 1).writeln; }
Aug 03 2018
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/3/18 12:17 PM, aliak wrote:
 Hi
 
 Is there a way to tell if an alias is to a template?
 
 I'm writing some algorithms and I need to distinguish between a binary 
 predicate that provides "less than" and one that provides "equal to" 
 semantics. So I have these two templates:
 
 template eq(alias pred) {
      alias eq = pred;
 }
 
 template lt(alias pred) {
      alias lt = pred;
 }
 
 Then in some place:
 
 static if (is(pred == eq)) {
    return eq(a, b);
 } else static if (is(pred == lt)) {
    return !lt(a, b) && !lt(b, a); // equality with less than predicate
 } else {
    // default assumptions about predicate
 }
 
 Then I can use it like:
 
 auto a = S!(eq!((a, b) => a == b)) ;
 auto a = S!(lt!((a, b) => a < b));
Once you have an alias, it's the original thing in all respects. So there's no way to get the specific alias that was used. That's not a bug, but a feature.
 
 I've tried std.traits.TemplateOf and __traits(isSame and also variations 
 of typeof and also traits.isInstanceOf. I wonder if I have to 
 parameterize eq and lt over a compile time sequence instead?
 
 Any tips to get this working?
I'd focus on encoding the lt/gt into a type. Much easier to test types. Perhaps a UDA works on an alias? I'm not sure. -Steve
Aug 04 2018
parent aliak <something something.com> writes:
On Saturday, 4 August 2018 at 12:54:49 UTC, Steven Schveighoffer 
wrote:
 Once you have an alias, it's the original thing in all 
 respects. So there's no way to get the specific alias that was 
 used. That's not a bug, but a feature.
Aha. Thanks.
 
 I've tried std.traits.TemplateOf and __traits(isSame and also 
 variations of typeof and also traits.isInstanceOf. I wonder if 
 I have to parameterize eq and lt over a compile time sequence 
 instead?
 
 Any tips to get this working?
I'd focus on encoding the lt/gt into a type. Much easier to test types. Perhaps a UDA works on an alias? I'm not sure. -Steve
Making it a type did indeed work (posted a reply with the solution to the previous poster). Cheers, - Ali
Aug 05 2018