Thread overview
No shortcircuit for static if or template constraints?
Oct 24, 2015
stewart
Oct 24, 2015
stewart
Oct 24, 2015
qsdfghjk
Oct 25, 2015
qsdfghjk
Oct 25, 2015
stewart
October 24, 2015
Hi All,

Given this code:

---
import std.traits;
import std.range;
import std.stdio;

enum isSupportedRange(T) = (isInputRange!T && isIntegral!(ForeachType!T));

void func(T)(T vals)
{
    static if(isSupportedRange!T) {
        // Do something with a range
    } else {
        // Do something with a scalar
    }
}

void main() {
    int a1 = 0;
    int[] a2 = [1,2,3];

    func(a1);
    func(a2);
}
---

I a compile error like so:

...std/traits.d(6136): Error: invalid foreach aggregate 0
hack.d(6): Error: template instance std.traits.ForeachType!int error instantiating
hack.d(10):        instantiated from here: isSupportedRange!int
hack.d(22):        instantiated from here: func!int

However, if I remove the Foreach part the "isInputRange!T" clearly fails.

I also tried overloading the function like so:

---
enum isSupportedRange(T) = (isInputRange!T && isIntegral!(ForeachType!T));

void func(T)(T vals) if(isSupportedRange!T) {
        // Do something with a range
}
void func(T)(T vals) if(isNumeric!T) {
    // Do something with a scalar
}
---

Again, if I remove the Foreach part and ignore element type of the range it works OK.

Am I doing something wrong?

Thanks,
stew
October 24, 2015
On Saturday, 24 October 2015 at 23:26:09 UTC, stewart wrote:
> Hi All,
>
> Given this code:
>
> ---
> import std.traits;
> import std.range;
> import std.stdio;
>
> enum isSupportedRange(T) = (isInputRange!T && isIntegral!(ForeachType!T));
>
> void func(T)(T vals)
> {
>     static if(isSupportedRange!T) {
>         // Do something with a range
>     } else {
>         // Do something with a scalar
>     }
> }
>
> void main() {
>     int a1 = 0;
>     int[] a2 = [1,2,3];
>
>     func(a1);
>     func(a2);
> }
> ---
>
> I a compile error like so:
>
> ...std/traits.d(6136): Error: invalid foreach aggregate 0
> hack.d(6): Error: template instance std.traits.ForeachType!int error instantiating
> hack.d(10):        instantiated from here: isSupportedRange!int
> hack.d(22):        instantiated from here: func!int
>
> However, if I remove the Foreach part the "isInputRange!T" clearly fails.
>
> I also tried overloading the function like so:
>
> ---
> enum isSupportedRange(T) = (isInputRange!T && isIntegral!(ForeachType!T));
>
> void func(T)(T vals) if(isSupportedRange!T) {
>         // Do something with a range
> }
> void func(T)(T vals) if(isNumeric!T) {
>     // Do something with a scalar
> }
> ---
>
> Again, if I remove the Foreach part and ignore element type of the range it works OK.
>
> Am I doing something wrong?
>
> Thanks,
> stew


Oh and the workaround I'm using is this:

---
void func(T)(T vals) {
    static if(isInputRange!T) {
        static if(isIntegral!(ForeachType!T)) {
            // Do something with range
        }
    } else {
        // do something with scalar
    }
}
---

which is a bit ugly.


October 24, 2015
On Saturday, 24 October 2015 at 23:34:19 UTC, stewart wrote:
> On Saturday, 24 October 2015 at 23:26:09 UTC, stewart wrote:
>> [...]
>
>
> Oh and the workaround I'm using is this:
>
> ---
> void func(T)(T vals) {
>     static if(isInputRange!T) {
>         static if(isIntegral!(ForeachType!T)) {
>             // Do something with range
>         }
>     } else {
>         // do something with scalar
>     }
> }
> ---
>
> which is a bit ugly.

Maybe this could work:

---
enum isSupportedRange(T) = isInputRange!T && is(ForeachType!T) && (isIntegral!(ElementType!T));
---

ElementType() should return exactly what you excpeted with ForeachType().
October 25, 2015
On Saturday, 24 October 2015 at 23:59:02 UTC, qsdfghjk wrote:
> On Saturday, 24 October 2015 at 23:34:19 UTC, stewart wrote:
>> On Saturday, 24 October 2015 at 23:26:09 UTC, stewart wrote:
>>> [...]
>>
>>
>> Oh and the workaround I'm using is this:
>>
>> ---
>> void func(T)(T vals) {
>>     static if(isInputRange!T) {
>>         static if(isIntegral!(ForeachType!T)) {
>>             // Do something with range
>>         }
>>     } else {
>>         // do something with scalar
>>     }
>> }
>> ---
>>
>> which is a bit ugly.
>
> Maybe this could work:
>
> ---
> enum isSupportedRange(T) = isInputRange!T && is(ForeachType!T) && (isIntegral!(ElementType!T));
> ---
>
> ElementType() should return exactly what you excpeted with ForeachType().

Oh no! there's been a copy & paste error. I actually meant:

---
enum isSupportedRange(T) = isInputRange!T  && (isIntegral!(ElementType!T));
October 25, 2015
On Saturday, 24 October 2015 at 23:59:02 UTC, qsdfghjk wrote:
> On Saturday, 24 October 2015 at 23:34:19 UTC, stewart wrote:
>> On Saturday, 24 October 2015 at 23:26:09 UTC, stewart wrote:
>>> [...]
>>
>>
>> Oh and the workaround I'm using is this:
>>
>> ---
>> void func(T)(T vals) {
>>     static if(isInputRange!T) {
>>         static if(isIntegral!(ForeachType!T)) {
>>             // Do something with range
>>         }
>>     } else {
>>         // do something with scalar
>>     }
>> }
>> ---
>>
>> which is a bit ugly.
>
> Maybe this could work:
>
> ---
> enum isSupportedRange(T) = isInputRange!T && is(ForeachType!T) && (isIntegral!(ElementType!T));
> ---
>
> ElementType() should return exactly what you excpeted with ForeachType().

Yep, that works, thanks!


I also found I can do it with __traits, but I think your way is cleaner.

enum bool isSupportedRange(T) = __traits(compiles, isInputRange!T && isIntegral!(ForeachType!T));

cheers,
stew