digitalmars.D.learn - templatized delegate
- Alex (112/112) May 22 2017 Hi, all
- Dukc (36/40) May 22 2017 The reason it does not work with a non-static member is that A
- Alex (11/51) May 22 2017 Yes, it does :)
- ag0aep6g (23/73) May 22 2017 Not only is a template not an lvalue, it's not any kind of value at all....
- Alex (9/36) May 22 2017 ok, I see the point, I think...
- Alex (16/20) May 23 2017 By the way, I'm not even sure, if variadics work in my case. I
- Nicholas Wilson (6/28) May 23 2017 Random is copy @disabled to prevent incorrect use.
- Stanislav Blinov (22/56) May 23 2017 void variadic(Args...)(auto ref Args args) { /* ... */ }
- Alex (11/32) May 23 2017 yes...
- Stanislav Blinov (6/46) May 23 2017 Ah, now I think I get it. You want to store a single delegate
- Alex (8/13) May 23 2017 Yes :)
- Alex (13/47) May 23 2017 No, you can't pass a ref into a variadic... if the test above is
- 9il (8/30) May 23 2017 1. Pass its pointer
Hi, all I have a question, how to handle a templated delegate. However, I'm not sure, if I'm going in the right direction, so I have three examples, and my question is about the third. 1. Here, a struct with an alias is defined and on its creation the delegate get known to the struct. Everything is ok. struct A(alias dg) { auto fun(int i, string s) { return dg(i, s); } } void main() { auto dlg(int i, string s) { import std.stdio; writeln(i, " ", s); } auto a = A!dlg(); a.fun(5, "a"); } 2. Now, I want to store the delegate in another struct. If I want to do this, I have to define the pointer as static. This is not intended at the beginning, but it's ok, as I know, that the delegate would be the same across all instances of B. struct A(alias dg) { auto fun(int i, string s) { return dg(i, s); } } struct B { A!dlgptr a; static void delegate(int, string) dlgptr; // here, without the "static" "need 'this' to access member dlgptr" rises this(void delegate(int, string) dlg) { dlgptr = dlg; } void fun(int i, string s) { a.fun(i, s); } } void main() { auto dlg(int i, string s) { import std.stdio; writeln(i, " ", s); } auto b = B(&dlg); b.fun(5, "a"); } 3. Now the hard stuff comes. I want to templatize my delegate. struct A(alias dg) { auto fun(T, U...)(T t, U u) { return dg!(T, U)(t, u); } } struct C { A!dlgptr a; /* static? */ template dlgptr(T, U...) { /* static? */ void delegate(T, U) dlgptr; } this(???) { ??? } void fun(T, U...)(T t, U args) { dlgptr!(T, U)(t, args); } } void main() { auto dlg(T, U...)(T t, U u) { import std.stdio; writeln(t, " ", u); } auto c = C(???); c.fun(5, "a"); // exception, obviously, as C is not initialized properly A!dlg a; a.fun(5, "a"); //Error: function test92.A!(dlg).A.fun!(int, string).fun cannot get frame pointer to test92.main.dlg!(int, string).dlg } Here, nothing works any more... I have no idea, what to pass to the struct C, as a template is not an lvalue. But even the direct initialization of A doesn't work... By the way, I found http://forum.dlang.org/post/xiycyjndqzbohjtjfjvh forum.dlang.org and http://www.digitalmars.com/d/archives/digitalmars/D/learn/delegate_template_and_alias_31092.html these both go into the right direction I think... but don't see, how to reformulate them... Thanks in advance :)
May 22 2017
On Monday, 22 May 2017 at 09:04:15 UTC, Alex wrote:2. Now, I want to store the delegate in another struct. If I want to do this, I have to define the pointer as static. This is not intended at the beginning, but it's ok, as I know, that the delegate would be the same across all instances of B.The reason it does not work with a non-static member is that A generated has no way of knowing where B that contains the delegate to be called resides. But it works when done this way: struct A(alias dg) { auto fun(T...)(T params) { return dg(params); } } struct B { A!((B b, int i, string a) => b.dlgptr(i, a)) a; void delegate(int, string) dlgptr; this(void delegate(int, string) dlg) { dlgptr = dlg; } void fun(int i, string s) { a.fun(this, i, s); } } void main() { auto dlg(int i, string s) { import std.stdio; writeln(i, " ", s); } auto b = B(&dlg); b.fun(5, "a"); } I wasn't in mood to look at C though, so I don't know if this helps.
May 22 2017
On Monday, 22 May 2017 at 20:38:27 UTC, Dukc wrote:On Monday, 22 May 2017 at 09:04:15 UTC, Alex wrote:Yes, it does :) The step to the C variant is, how to rewrite the lines A!((B b, int i, string a) => b.dlgptr(i, a)) a; and this(void delegate(int, string) dlg) if I want to define my delegate as a template: template dlgptr(T, U...) { void delegate(T, U) dlgptr; }2. Now, I want to store the delegate in another struct. If I want to do this, I have to define the pointer as static. This is not intended at the beginning, but it's ok, as I know, that the delegate would be the same across all instances of B.The reason it does not work with a non-static member is that A generated has no way of knowing where B that contains the delegate to be called resides. But it works when done this way: struct A(alias dg) { auto fun(T...)(T params) { return dg(params); } } struct B { A!((B b, int i, string a) => b.dlgptr(i, a)) a; void delegate(int, string) dlgptr; this(void delegate(int, string) dlg) { dlgptr = dlg; } void fun(int i, string s) { a.fun(this, i, s); } } void main() { auto dlg(int i, string s) { import std.stdio; writeln(i, " ", s); } auto b = B(&dlg); b.fun(5, "a"); } I wasn't in mood to look at C though, so I don't know if this helps.
May 22 2017
On 05/22/2017 11:04 AM, Alex wrote:3. Now the hard stuff comes. I want to templatize my delegate. struct A(alias dg) { auto fun(T, U...)(T t, U u) { return dg!(T, U)(t, u); } } struct C { A!dlgptr a; /* static? */ template dlgptr(T, U...) { /* static? */ void delegate(T, U) dlgptr; } this(???) { ??? } void fun(T, U...)(T t, U args) { dlgptr!(T, U)(t, args); } } void main() { auto dlg(T, U...)(T t, U u) { import std.stdio; writeln(t, " ", u); } auto c = C(???); c.fun(5, "a"); // exception, obviously, as C is not initialized properly A!dlg a; a.fun(5, "a"); //Error: function test92.A!(dlg).A.fun!(int, string).fun cannot get frame pointer to test92.main.dlg!(int, string).dlg } Here, nothing works any more... I have no idea, what to pass to the struct C, as a template is not an lvalue.Not only is a template not an lvalue, it's not any kind of value at all. It doesn't have a type. You can't have a variable holding a template. You can't pass it as an argument. But a template is a symbol. You can pass it in an alias parameter. So to pass dlg to C, you have to make C a template with an alias parameter, like A is.But even the direct initialization of A doesn't work...`A!dlg a;` works. Calling `fun` doesn't. A.fun instantiates dlg, resulting in a delegate that should be able to access main's stuff. But it's not guaranteed that main is active when A.fun is called. You could have returned `a` from main before calling fun. For an actual delegate, a closure would be made in that case. But dlg isn't a delegate, it's a template. I guess it's not possible (or not feasible, or not implemented) to create a closure a template like this. If you don't actually need dlg to access main's stuff, you can make it static. It's a function then and the delegate weirdness doesn't apply. For another approach to your problem, maybe have a look at run-time variadic arguments: https://dlang.org/spec/function.html#d_style_variadic_functions With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.
May 22 2017
On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:On 05/22/2017 11:04 AM, Alex wrote:Aha... ok, I see...[...]Not only is a template not an lvalue, it's not any kind of value at all. It doesn't have a type. You can't have a variable holding a template. You can't pass it as an argument. But a template is a symbol. You can pass it in an alias parameter. So to pass dlg to C, you have to make C a template with an alias parameter, like A is.ok, I see the point, I think...[...]`A!dlg a;` works. Calling `fun` doesn't. A.fun instantiates dlg, resulting in a delegate that should be able to access main's stuff. But it's not guaranteed that main is active when A.fun is called. You could have returned `a` from main before calling fun. For an actual delegate, a closure would be made in that case. But dlg isn't a delegate, it's a template. I guess it's not possible (or not feasible, or not implemented) to create a closure a template like this.If you don't actually need dlg to access main's stuff, you can make it static. It's a function then and the delegate weirdness doesn't apply.yeah... no :) the function inside the main has to have access to the main stuff. Its the pointer inside C which could be static, if this would help. So long, I go for the enhanced second variant...For another approach to your problem, maybe have a look at run-time variadic arguments: https://dlang.org/spec/function.html#d_style_variadic_functions With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.Hm... You are probably right... and variadic functions do not really match the idea...
May 22 2017
On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function: import std.stdio; import mir.random; void main() { Random rndGen = Random(unpredictableSeed); fun(rndGen); } void fun(...) { } Yields "... is not copyable because it is annotated with disable" :)
May 23 2017
On Tuesday, 23 May 2017 at 10:30:56 UTC, Alex wrote:On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:Random is copy disabled to prevent incorrect use. You need to pass it by ref or pointer. I dont know if you can pass variables as ref to a variadic, but you should be able to pass it by address. fun(&rndGen);With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function: import std.stdio; import mir.random; void main() { Random rndGen = Random(unpredictableSeed); fun(rndGen); } void fun(...) { } Yields "... is not copyable because it is annotated with disable" :)
May 23 2017
On Tuesday, 23 May 2017 at 10:42:54 UTC, Nicholas Wilson wrote:On Tuesday, 23 May 2017 at 10:30:56 UTC, Alex wrote:void variadic(Args...)(auto ref Args args) { /* ... */ } This infers whether you pass lvalues or rvalues. If passing further down the chain of such calls is needed, one can use std.functional : fowrard : void variadic(Args...)(auto ref Args args) { import std.functional : forward; doStuff(forward!args); } void doStuff(Args...)(auto ref Args args) { /* ... */ } 'forward' aliases ref arguments (i.e. passed lvalues) and moves value arguments (i.e. passed rvalues). If a value is not copyable, it may be move-able (check the docs though, it may not be that either). void fun(Args...)(auto ref Args args) { /*...*/ } import std.algorithm : move; auto a = NonCopyable(42); fun(move(a)); // or: func(NonCopyable(42));On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:Random is copy disabled to prevent incorrect use. You need to pass it by ref or pointer. I dont know if you can pass variables as ref to a variadic, but you should be able to pass it by address. fun(&rndGen);With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function: import std.stdio; import mir.random; void main() { Random rndGen = Random(unpredictableSeed); fun(rndGen); } void fun(...) { } Yields "... is not copyable because it is annotated with disable" :)
May 23 2017
On Tuesday, 23 May 2017 at 11:05:09 UTC, Stanislav Blinov wrote:void variadic(Args...)(auto ref Args args) { /* ... */ } This infers whether you pass lvalues or rvalues. If passing further down the chain of such calls is needed, one can use std.functional : fowrard :yes...void variadic(Args...)(auto ref Args args) { import std.functional : forward; doStuff(forward!args); } void doStuff(Args...)(auto ref Args args) { /* ... */ } 'forward' aliases ref arguments (i.e. passed lvalues) and moves value arguments (i.e. passed rvalues). If a value is not copyable, it may be move-able (check the docs though, it may not be that either). void fun(Args...)(auto ref Args args) { /*...*/ }yes...import std.algorithm : move; auto a = NonCopyable(42); fun(move(a)); // or: func(NonCopyable(42));the problem, that I have is, that I would like to use the templated approach, but I don't have the function, but only a delegate, so: template(T, U...) { void delegate(ref T neededInput, ref U ignoredInput) dgPtr; } Not sure, if this is possible to handle at all...
May 23 2017
On Tuesday, 23 May 2017 at 11:45:13 UTC, Alex wrote:On Tuesday, 23 May 2017 at 11:05:09 UTC, Stanislav Blinov wrote:Ah, now I think I get it. You want to store a single delegate that could be called with different sets of arguments? No, you can't do that: you need an actual delegate instance, and for that, you need to know the signature, at least when instantiating C.void variadic(Args...)(auto ref Args args) { /* ... */ } This infers whether you pass lvalues or rvalues. If passing further down the chain of such calls is needed, one can use std.functional : fowrard :yes...void variadic(Args...)(auto ref Args args) { import std.functional : forward; doStuff(forward!args); } void doStuff(Args...)(auto ref Args args) { /* ... */ } 'forward' aliases ref arguments (i.e. passed lvalues) and moves value arguments (i.e. passed rvalues). If a value is not copyable, it may be move-able (check the docs though, it may not be that either). void fun(Args...)(auto ref Args args) { /*...*/ }yes...import std.algorithm : move; auto a = NonCopyable(42); fun(move(a)); // or: func(NonCopyable(42));the problem, that I have is, that I would like to use the templated approach, but I don't have the function, but only a delegate, so: template(T, U...) { void delegate(ref T neededInput, ref U ignoredInput) dgPtr; } Not sure, if this is possible to handle at all...
May 23 2017
On Tuesday, 23 May 2017 at 16:38:14 UTC, Stanislav Blinov wrote:Ah, now I think I get it. You want to store a single delegate that could be called with different sets of arguments? No, you can't do that: you need an actual delegate instance, and for that, you need to know the signature, at least when instantiating C.Yes :) or, just to differentiate between the used and unused parameters, without loosing their types and attributes. But that's a minor problem, the solution with full signature https://forum.dlang.org/post/ekbpjsuyqprusyasmjsm forum.dlang.org#post-svvgcrymplmyondhuogt:40forum.dlang.org works also well, as the effort to name everything is not so big in my case...
May 23 2017
On Tuesday, 23 May 2017 at 10:42:54 UTC, Nicholas Wilson wrote:On Tuesday, 23 May 2017 at 10:30:56 UTC, Alex wrote:Yes, I'm aware of this...On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:Random is copy disabled to prevent incorrect use.With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function: import std.stdio; import mir.random; void main() { Random rndGen = Random(unpredictableSeed); fun(rndGen); } void fun(...) { } Yields "... is not copyable because it is annotated with disable" :)You need to pass it by ref or pointer. I dont know if you can pass variables as ref to a variadic, but you should be able to pass it by address. fun(&rndGen);No, you can't pass a ref into a variadic... if the test above is written correct. And no, I can't pass it by adress, as I don't know apriori, whether the very parameter which gets the random generator is already a part of the variadic parameters, or a well defined ref parameter. Especially, there are some functions for both cases. While the argument list remains the same, the acceptor part is meant to work with it somehow. The other way around would be, to manipulate the argument list, which is shared...
May 23 2017
On 05/23/2017 01:30 PM, Alex wrote:And no, I can't pass it by adress, as I don't know apriori, whether the very parameter which gets the random generator is already a part of the variadic parameters, or a well defined ref parameter.A (run-time) variadic delegate isn't flexible like that. When you have a `void delegate(...)`, then there are no non-variadic parameters. You know both in the caller and in the callee that passing by ref is not an option. So you can define that uncopyable types are passed by pointer. Going this route means you have to make all your delegates variadic (this might be annoying). A.fun can remain a variadic template. It can also have ref parameters, but then you have to detect uncopyable types and pass pointers to the delegate. Something like this: ---- import core.vararg; import std.meta: AliasSeq, staticMap; import std.traits: isCopyable; struct A { void delegate(...) dg; auto fun(T, U ...)(T t, auto ref U u) { template UncopyableToPointer(T) { static if (!isCopyable!T) alias UncopyableToPointer = T*; else alias UncopyableToPointer = T; } alias U2 = staticMap!(UncopyableToPointer, U); U2 u2; foreach (i, E; U) { static if (!isCopyable!E) u2[i] = &u[i]; else u2[i] = u[i]; } return dg(t, u2); } } struct SomeStructThatIsNotCopyable { disable this(this); } void main() { void dlg(...) { import std.stdio; foreach (i, t; _arguments) { foreach (T; AliasSeq!(int, string, SomeStructThatIsNotCopyable*)) { if (t == typeid(T)) { static if (is(T : U*, U) && !isCopyable!U) { write("uncopyable type"); } else write(_argptr.va_arg!T); } } /* otherwise: don't know how to handle the type */ write(" "); } writeln(); } auto a = A(&dlg); SomeStructThatIsNotCopyable s; a.fun(5, "a", /* by ref: */ s, /* or by pointer: */ &s); } ---- That's not exactly pretty, of course. Both A.fun and the delegate are quite complicated. But it might be workable, if run-time variadics are acceptable. I wouldn't be surprised if the problem can be solved more elegantly. But I don't see how at the moment.
May 23 2017
On Tuesday, 23 May 2017 at 18:14:34 UTC, ag0aep6g wrote:Something like this: ---- import core.vararg; import std.meta: AliasSeq, staticMap; import std.traits: isCopyable; struct A { void delegate(...) dg; auto fun(T, U ...)(T t, auto ref U u) { template UncopyableToPointer(T) { static if (!isCopyable!T) alias UncopyableToPointer = T*; else alias UncopyableToPointer = T; } alias U2 = staticMap!(UncopyableToPointer, U); U2 u2; foreach (i, E; U) { static if (!isCopyable!E) u2[i] = &u[i]; else u2[i] = u[i]; } return dg(t, u2); } } struct SomeStructThatIsNotCopyable { disable this(this); } void main() { void dlg(...) { import std.stdio; foreach (i, t; _arguments) { foreach (T; AliasSeq!(int, string, SomeStructThatIsNotCopyable*)) { if (t == typeid(T)) { static if (is(T : U*, U) && !isCopyable!U) { write("uncopyable type"); } else write(_argptr.va_arg!T); } } /* otherwise: don't know how to handle the type */ write(" "); } writeln(); } auto a = A(&dlg); SomeStructThatIsNotCopyable s; a.fun(5, "a", /* by ref: */ s, /* or by pointer: */ &s); } ---- That's not exactly pretty, of course. Both A.fun and the delegate are quite complicated. But it might be workable, if run-time variadics are acceptable. I wouldn't be surprised if the problem can be solved more elegantly. But I don't see how at the moment.That's cool :) but anyway, even if I have such params, there are not much of them, so it just a minor semantic issue to explicitely name them and their types instead of showing, that they are passed but not used inside dlg. And thanks a lot to all for great ideas :)
May 23 2017
On Tuesday, 23 May 2017 at 10:30:56 UTC, Alex wrote:On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:1. Pass its pointer 2. Use variadic template with auto ref: ``` void foo(T...)(auto ref T tup) { } ```With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function: import std.stdio; import mir.random; void main() { Random rndGen = Random(unpredictableSeed); fun(rndGen); } void fun(...) { } Yields "... is not copyable because it is annotated with disable" :)
May 23 2017