A template for method forwarding?
dsimcha
dsimcha at yahoo.com
Fri Dec 12 12:54:28 PST 2008
== Quote from Bill Baxter (wbaxter at gmail.com)'s article
> Let's say you want to use object composition instead of inheritance.
> Now you want to forward half-a-dozen method from the new to class to
> the composed class, like so:
> class NewClass
> {
> ImplT implementor;
> ...
> // Do some method forwarding
> void func1(int a, float b) { implementor.func1(a,b); }
> string func2(string s) { return implementor.func2(s); }
> T aTemplate(T)(T val, T[] arr) { return implementor!(T)(val,arr); }
> ...
> }
> It becomes pretty tedious to type all these things out, and if the
> base class changes a method signature, you have to remember to do it
> in the parent class too.
> So the challenge is to write some kind of template that does the
> necessary argument deduction to implement a forwarder just by
> mentioning the name of the method and the object to forward to.
> Something like this perhaps for the usage syntax:
> mixin call_forward!(implementor, "func1");
> mixin call_forward!(implementor, "func2");
> mixin call_forward!(implementor, "aTemplate");
> Is it possible? Somebody must have done something like this already.
> --bb
That was fun. Disclaimer: This probably is impossible in D1. This is probably
strictly a D2 hack. The one bug I see is that this template will not handle
default parameters correctly (or at all).
import std.traits;
template Forward(string clName, Methods...) {
static if(Methods.length == 1) {
mixin ForwardImpl!(clName, Methods[0]);
} else {
mixin ForwardImpl!(clName, Methods[0]);
mixin Forward!(clName, Methods[1..$]);
}
}
template ForwardImpl(string clName, string method) {
private mixin("alias ParameterTypeTuple!(" ~ clName ~ "."
~ method ~ ") params;");
private mixin("alias ReturnType!(" ~ clName ~ "."
~ method ~ ") retType;");
static if(is(retType == void)) {
mixin("void " ~ method ~ "(Tuple!" ~ params.stringof ~ " args){" ~
clName ~ "." ~ method ~ "(args); }");
} else {
mixin(retType.stringof ~ " " ~ method ~
"(Tuple!" ~ params.stringof ~ " args){ return " ~ clName ~ "."
~ method ~ "(args); }");
}
}
template Tuple(T...) {
alias T Tuple;
}
// Test code.
class Mul { // The class you are delegating to.
this() {}
uint multiply(uint l, uint r) {
return l * r;
}
uint divide(uint l, uint r) {
return l / r;
}
void testVoid() {
writeln("Success: testVoid");
}
}
class Arithmetic {
Mul mul;
this() {
mul = new Mul;
}
uint add(uint l, uint r) {
return l + r;
}
mixin Forward!("mul", "multiply", "divide", "testVoid");
}
import std.stdio;
void main() {
auto arith = new Arithmetic;
writeln(arith.multiply(2, 3));
writeln(arith.divide(4, 2));
arith.testVoid();
}
More information about the Digitalmars-d
mailing list