www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Array of member functions generated at compile time

reply "Jason Langenauer" <jason jasonlangenauer.com> writes:
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
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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