== Quote from Bill Baxter (wbax...@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(); }