Michel Fortin wrote:
The thing is that the name of that "catchAllHandlerFunc" function needs
to be standardised for it to work with runtime reflection.
I agree with this wholeheartedly.
However, opDotExp would be hamstringed if it were made to serve this
function.
Since classes can implement interfaces, you could expose an interface
IDispatch or the like. This doesn't suffice for structs, though.
Let's look at the swizzle case. You want a class or a struct with a
function for every permutation of "xwyz". Beside doing that manually,
here's what you can do:
Solution A: use a mixin. This will add 256 functions to your struct, and
those functions will appear in the functionList used by
invokeViaReflection.
Solution B.1: use a templated catch-all function, and use the name to
instanciate the catch-all. Calling the function will work at compile
time, but at runtime invokeViaReflection is left in the dust.
Solution B.2: in addition to the templated catch-all function in B.1,
add a runtime catch-all. This is about twice the work, but
invokeViaReflection can work with those functions.
The standard form will be something like:
class Dispatch : IDispatch
{
auto opDotExp(string name)(...) { return dispatch(name, _arguments,
_argptr); }
auto dispatch(string name, ...)
{
// do stuff
}
}
This isn't much added work.
Now, let's look at the proxy case, where you want to forward function
calls to another object. In fact, there are two variant of this case:
one where you know the type at compile-time, one where you don't (you
only know the base class) but still want to forward all calls.
Solution A: use a mixin. The mixin will create a wrapper function for
all functions in the wrapped object it can find using compile-time
reflection, and those functions will appear in the functionList used by
invokeViaReflection.
That's a lot of work, but it can get you a performance increase in the
case where you know something about the class at compile time (for
instance, you have an object that implements a particular interface, but
you want to call non-interface functions via the wrapper).
Of course, you could manually forward methods as well and get the same
performance increase. But that would be more difficult to write.
Note that I'm not that much against a templated opDot, I just want to
point out its drawbacks for reflection. I'm also unconvinced of its
usefulness considering you can do the same things better using mixins
leaving only the runtime case to be solved, where you are better served
without a template anyway.
Well, you can do the same things with some other advantages with mixins,
but it's harder to write.
I think the appropriate solution is to add a solver to the compiler that
can determine valid inputs for opDotExp and, if that set is below a
threshold, unroll the template into regular member functions.
Or, you know, just implement a static foreach that you can use in
templates. And anything else that we can think of that's reasonable to
make the mixin solution easier to work with.
If that's accomplished, there'd be no reason to have opDotExp as a template.