www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - No shortcircuit for static if or template constraints?

reply stewart <growlercab gmail.com> writes:
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
Oct 24 2015
parent reply stewart <growlercab gmail.com> writes:
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.
Oct 24 2015
parent reply qsdfghjk <qsdfghjk niwhere.hj> writes:
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().
Oct 24 2015
next sibling parent qsdfghjk <qsdfghjk niwhere.hj> writes:
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));
Oct 24 2015
prev sibling parent stewart <growlercab gmail.com> writes:
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
Oct 24 2015