digitalmars.D.learn - Template constraint and specializations
- Ed McCardell (13/13) Mar 23 2012 Is there a way to write a template constraint that matches any
- Andrej Mitrovic (16/18) Mar 23 2012 Nope. But there are simple workarounds:
- Ed McCardell (5/13) Mar 23 2012 Thanks! I was tempted to try something hacky for the constraint, like
- Philippe Sigaud (28/40) Mar 23 2012 Another solution that does not require you to add an _isFoo member:
- Andrej Mitrovic (36/38) Mar 23 2012 That can't work. For a Foo!int your code will expand like so:
- Philippe Sigaud (37/39) Mar 23 2012 ? It works for me:
- Andrej Mitrovic (18/19) Mar 23 2012 Yes but check the isA template. It seems there's something causing a
- Philippe Sigaud (4/9) Mar 24 2012 Then the generic template should be
- bearophile (17/18) Mar 23 2012 Why isn't something similar to this working?
Is there a way to write a template constraint that matches any specialization of a given type? For example can the following be done without having to write out every combination of feature1 and feature2: class Foo(bool feature1, bool feature2) { ... } void useFoo(T)(T foo) if (is(T == Foo!(false, false)) || is(T == Foo!(false, true)) || is(T == Foo!(true, false)) || is(T == Foo!(true, true))) { // call methods of foo that don't change based on feature1/feature2 } Thanks, --Ed
Mar 23 2012
On 3/23/12, Ed McCardell <edmccard hotmail.com> wrote:Is there a way to write a template constraint that matches any specialization of a given type?Nope. But there are simple workarounds: class Foo(bool feature1, bool feature2) { enum _isFoo = true; } template isFoo(T) { enum bool isFoo = __traits(hasMember, T, "_isFoo"); } void useFoo(T)(T foo) if (isFoo!T) { // call methods of foo that don't change based on feature1/feature2 } void main() { Foo!(true, false) foo; useFoo(foo); }
Mar 23 2012
On 03/23/2012 04:14 AM, Andrej Mitrovic wrote:On 3/23/12, Ed McCardell<edmccard hotmail.com> wrote:Thanks! I was tempted to try something hacky for the constraint, like if (T.stringof == "Foo") but tagging the type with an enum works better all around. --EdIs there a way to write a template constraint that matches any specialization of a given type?Nope. But there are simple workarounds: class Foo(bool feature1, bool feature2) { enum _isFoo = true; } template isFoo(T) { enum bool isFoo = __traits(hasMember, T, "_isFoo"); }
Mar 23 2012
On Fri, Mar 23, 2012 at 10:17, Ed McCardell <edmccard hotmail.com> wrote:Another solution that does not require you to add an _isFoo member: use template function instantiation: template isFoo(T) { enum bool isFoo =3D __traits(compiles, { void testFoo(Args...)(Foo!Args arg); testFoo(T.init); }); } testFoo is a function that accepts any Foo!( ... ) for any ... The second line tests it on a value of type T (T.init). This can be generalized even further, to create any template-testing functi= on: template isA(alias Foo) { template isA(T) { enum bool isA =3D __traits(compiles, { void tester(Args...)(Foo!Args args); tester(T.init);}); } } usage: alias isA!Foo isFoo; template useFoo(T) if (isFoo!T) { .... }Is there a way to write a template constraint that matches any specialization of a given type?Nope. But there are simple workarounds: class Foo(bool feature1, bool feature2) { enum _isFoo =3D true; } template isFoo(T) { =C2=A0 =C2=A0 enum bool isFoo =3D __traits(hasMember, T, "_isFoo"); }
Mar 23 2012
On 3/23/12, Philippe Sigaud <philippe.sigaud gmail.com> wrote:testFoo is a function that accepts any Foo!( ... ) for any ... The second line tests it on a value of type T (T.init).That can't work. For a Foo!int your code will expand like so: // original code void tester(Args...)(Foo!Args args); tester(T.init); void tester(Args...)(Foo!Args args); tester((Foo!int).init); // T is a template instance void tester(Foo!int)(Foo!(Foo!int) args); // Args.. becomes the template instance type tester((Foo!int).init); See for yourself: template isA(alias Foo) { template isA(T) { //~ pragma(msg, T.init); enum bool isA = __traits(compiles, { void tester(Args...)(Foo!Args args); tester(T.init); }); } } struct Foo(T) { } alias isA!Foo isFoo; void useFoo(T)(T t) if (isFoo!T) // no-go { } void main() { Foo!int foo; useFoo(foo); }
Mar 23 2012
On Fri, Mar 23, 2012 at 21:27, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:That can't work. For a Foo!int your code will expand like so:See for yourself:? It works for me: template isBar(T) { enum isBar = __traits(compiles, { void tester(Args...)(Bar!Args arg) {} tester(T.init); }); } template isFoo(T) { enum isFoo = __traits(compiles, { void tester(Arg)(Foo!Arg arg) {} tester(T.init); }); } struct Foo(T) { } struct Bar(T...) {} void useFoo(T)(T t) if (isFoo!T) { } void useBar(T)(T t) if (isBar!T) { } void main() { Foo!int foo; useFoo(foo); Bar!(int, string, double) bar; useBar(bar); }
Mar 23 2012
On 3/23/12, Philippe Sigaud <philippe.sigaud gmail.com> wrote:It works for meYes but check the isA template. It seems there's something causing a nested variadic template to fail. This won't work in a template constraint (it returns false): template isA(alias Foo) { template isA(T) { enum bool isA = __traits(compiles, { void tester(Args...)(Foo!(Args) args); tester(T.init); }); } } alias isA!Foo isFoo; But if you change "Args..." to "Args" then it works, although only for single-type templates.. I'm not sure what's going on..
Mar 23 2012
On Fri, Mar 23, 2012 at 23:19, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:Yes but check the isA template. It seems there's something causing a nested variadic template to fail. This won't work in a template constraint (it returns false):But if you change "Args..." to "Args" then it works, although only for single-type templates.. I'm not sure what's going on..Then the generic template should be enum isA = ( Arg case ) || (Args... case)
Mar 24 2012
Andrej Mitrovic:Nope. But there are simple workarounds:Why isn't something similar to this working? import std.traits: Unqual; class Foo(bool feature1, bool feature2) {} template isFoo(T) { static if (is(Unqual!T Unused : Foo!Features, Features...)) { enum isFoo = true; } else { enum isFoo = false; } } void main() { auto f1 = new Foo!(true, false)(); static assert(isFoo!(typeof(f1))); } Bye, bearophile
Mar 23 2012