Thread overview
Can you tell if an template alias parameter is of a specific template?
Aug 03, 2018
aliak
Aug 03, 2018
Hakan Aras
Aug 03, 2018
aliak
Aug 05, 2018
aliak
August 03, 2018
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
August 03, 2018
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.
August 03, 2018
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;
}

August 04, 2018
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
August 05, 2018
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