Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
March 23, 2012 Template constraint and specializations | ||||
---|---|---|---|---|
| ||||
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 |
March 23, 2012 Re: Template constraint and specializations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ed McCardell | 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);
}
|
March 23, 2012 Re: Template constraint and specializations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | On 03/23/2012 04:14 AM, Andrej Mitrovic wrote:
> 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");
> }
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.
--Ed
|
March 23, 2012 Re: Template constraint and specializations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | 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
|
March 23, 2012 Re: Template constraint and specializations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ed McCardell | On Fri, Mar 23, 2012 at 10:17, 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");
>> }
Another solution that does not require you to add an _isFoo member: use template function instantiation:
template isFoo(T)
{
enum bool isFoo = __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 function:
template isA(alias Foo)
{
template isA(T)
{
enum bool isA = __traits(compiles, { void
tester(Args...)(Foo!Args args); tester(T.init);});
}
}
usage:
alias isA!Foo isFoo;
template useFoo(T) if (isFoo!T)
{
....
}
|
March 23, 2012 Re: Template constraint and specializations | ||||
---|---|---|---|---|
| ||||
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);
}
|
March 23, 2012 Re: Template constraint and specializations | ||||
---|---|---|---|---|
| ||||
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); } |
March 23, 2012 Re: Template constraint and specializations | ||||
---|---|---|---|---|
| ||||
On 3/23/12, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
> It works for me
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):
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..
|
March 24, 2012 Re: Template constraint and specializations | ||||
---|---|---|---|---|
| ||||
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) |
Copyright © 1999-2021 by the D Language Foundation