digitalmars.D.learn - An issue with setting delegates via templates
- Andrej Mitrovic (47/47) Oct 25 2011 class Foo
- travert phare.normalesup.org (Christophe) (13/73) Oct 27 2011 Once you are inside set, handler is just a function and context pointer
- Andrej Mitrovic (39/39) Oct 27 2011 So it seems this is an issue with a newer signals implementation.
- travert phare.normalesup.org (Christophe Travert) (22/25) Nov 02 2011 OK, so there is indeed a filter to find a suitable delegate to load:
class Foo { void func(double) { } void func(int) { } void set(T)(T handler) { dg = handler; } void delegate(int) dg; } void main() { auto foo = new Foo; foo.set(&foo.func); // NG, func(double) is picked up first } Error: cannot implicitly convert expression (handler) of type void delegate(double _param_0) to void delegate(int) The problem here is that `void func(double)` is declared first, and that's what the address-of operator picks up. If you swap the two overloads this sample will compile. How could this be worked around /while still using templates/? There can only be one topmost function overload, so with two overloads this can be worked around, but with more overloads this workaround can't be used. I've almost found a workaround via the getOverloads trait: import std.traits; class Foo { void func(double) { } void func(int) { } void set(T)(T handler) { dg = handler; } void delegate(int) dg; } void main() { auto foo = new Foo; foo.set(&__traits(getOverloads, foo, "func")[1]); } This works, but I can't use this from within a template. IOW, I can't pass a function pointer to a template and then figure out if that function is actually an overload of some class. I'd need more powerful compile-time features for that. If I were able to do that then I could enumerate all the overloads and pick one if it matches the type of 'dg'. It's kind of overkill but it could work, at least theoretically. Otherwise I'd really need a way to explicitly specify which function overload to pass when I use the address-of operator, but that would probably have to be a language feature.
Oct 25 2011
Andrej Mitrovic , dans le message (digitalmars.D.learn:30286), a écrit :class Foo { void func(double) { } void func(int) { } void set(T)(T handler) { dg = handler; } void delegate(int) dg; } void main() { auto foo = new Foo; foo.set(&foo.func); // NG, func(double) is picked up first } Error: cannot implicitly convert expression (handler) of type void delegate(double _param_0) to void delegate(int) The problem here is that `void func(double)` is declared first, and that's what the address-of operator picks up. If you swap the two overloads this sample will compile. How could this be worked around /while still using templates/? There can only be one topmost function overload, so with two overloads this can be worked around, but with more overloads this workaround can't be used. I've almost found a workaround via the getOverloads trait: import std.traits; class Foo { void func(double) { } void func(int) { } void set(T)(T handler) { dg = handler; } void delegate(int) dg; } void main() { auto foo = new Foo; foo.set(&__traits(getOverloads, foo, "func")[1]); } This works, but I can't use this from within a template. IOW, I can't pass a function pointer to a template and then figure out if that function is actually an overload of some class. I'd need more powerful compile-time features for that. If I were able to do that then I could enumerate all the overloads and pick one if it matches the type of 'dg'. It's kind of overkill but it could work, at least theoretically. Otherwise I'd really need a way to explicitly specify which function overload to pass when I use the address-of operator, but that would probably have to be a language feature.Once you are inside set, handler is just a function and context pointer pair. Finding out what are the overloads of handler just with it's adress will be very complicated for a very limitted usage. Maybe an approach would be to make handler an alias rather than a delegate (but this won't work here because you have to pass foo along with &Foo.func...). Why does Foo.set has to be a template ? The obvious workarround is to make set expect a void delegate(int), instead of an undefined type, since this is the only type you can assign to dg. I think I need a better example to understand why set is a template, and how to work arround that.
Oct 27 2011
So it seems this is an issue with a newer signals implementation. The old one works: import std.signals; struct Foo { mixin Signal!(int) sig; } class Bar { void x(string) { } void x(int) { } } void main() { Foo foo; auto bar = new Bar; foo.sig.connect(&bar.x); foo.sig.emit(1); } But the new reimplementation (not in Phobos) doesn't: import signalsnew; struct Foo { Signal!(int) sig; // no need for mixin in new signals } class Bar { void x(string) { } void x(int) { } } void main() { Foo foo; auto bar = new Bar; foo.sig.connect(&bar.x); foo.sig.emit(1); } The new one: https://gist.github.com/1194497 I'll investigate this further then.
Oct 27 2011
Andrej Mitrovic , dans le message (digitalmars.D.learn:30315), a écrit :The new one: https://gist.github.com/1194497 I'll investigate this further then.OK, so there is indeed a filter to find a suitable delegate to load: trusted T connect(T)(T handler) if(isHandler!(T, Types)); But only the first Bar.x function is picked and given to isHandler!(T, int) to check it can be called. Bar.x(double) do not pass this filter. I guess if the signature were: T connect(void handler(Types)); T connect(bool handler(Types)); etc... or maybe T connect(T : void handler(Types)) (T handler); T connect(T : bool handler(Types)) (T handler); etc... Then the compiler should be able to select the right Bar.x method. But with the isHandler filter,it is not able to find it. I don't see a way to improve isHandler to make it able to find the right Bar.x method, without modification of the compiler*, but I am not an expert here. * the compiler should allow all overloads of a function given as a template argument to be tested against the filter to choose the right one, and complain if several overloads match the filter. -- Christophe
Nov 02 2011