digitalmars.D.learn - Array of member functions generated at compile time
- Jason Langenauer (35/35) Apr 25 2008 Hi,
- Jarrett Billingsley (22/49) Apr 25 2008 Problem number 1: you're using the wrong kind of mixin. You want a stri...
Hi, I'm trying to generate at compile-time an associative array of function pointers to class member functions where the key in the array is the name of the member function itself. What my best attempt so far has been is as follows, which doesn't compile: class ApplicationController { void function()[char[]] action_map; this() { mixin ArrayMap!(build_code(__traits( derivedMembers, ApplicationController ))); } char[] build_code(invariant(char)[][] actions) { char[] code; foreach(invariant(char)[] action; actions) { code ~= "action_map[\"" ~ action ~ "\"] = &(" ~ action ~ ");"; } return code; } template ArrayMap(char[] code) { const ArrayMap = code; } } Can anyone suggest other ways to achieve what I want to do? Or point out where I might be going wrong in the above? Many thanks Jason P.S. The compiler error I get is: applicationcontroller.d(9): Error: expression this.build_code(["action_map","_ctor","build_code","ArrayMap"]) is not a valid template value argument
Apr 25 2008
"Jason Langenauer" <jason jasonlangenauer.com> wrote in message news:mailman.466.1209133945.2351.digitalmars-d-learn puremagic.com...Hi, I'm trying to generate at compile-time an associative array of function pointers to class member functions where the key in the array is the name of the member function itself. What my best attempt so far has been is as follows, which doesn't compile: class ApplicationController { void function()[char[]] action_map; this() { mixin ArrayMap!(build_code(__traits( derivedMembers, ApplicationController ))); }Problem number 1: you're using the wrong kind of mixin. You want a string mixin, which just involves putting parens around the mixin argument: mixin(ArrayMap!(build_code(__traits(derivedMembers, ApplicationController))));char[] build_code(invariant(char)[][] actions) { char[] code; foreach(invariant(char)[] action; actions) { code ~= "action_map[\"" ~ action ~ "\"] = &(" ~ action ~ ");"; } return code; }Problems 2 and 3: this function can't be evaluated at compile time for 2 reasons. One, it's not static, so make it so. Two, for some reason (that I really don't feel like wrapping my head around), the string concatenation fails as-is. If you change it to: code ~= "action_map[\"" ~ action.dup ~ "\"] = &(" ~ action.dup ~ ");"; (note the dups), it works.template ArrayMap(char[] code) { const ArrayMap = code; } }Now, all that will make it work like you expect. However, it doesn't quite do what you want because (1) derivedMembers gives you all members including data members and not just methods, and (2) unless a member really is a void function(), you're not going to be able to put it in that AA. If you take the address of a member function in a non-static context anyway, you're going to end up with a delegate, not a function pointer. So either you'll have to filter, at compile time, the list of methods that you want to wrap and only allow those with a void() signature, or you'd have to do something a bit crazier and come up with some kind of variant delegate type that would allow any kind of delegate to be stored in that AA.
Apr 25 2008