Cool. I don't see anything D2 specific there, so I think it should work in D1 ok. std.traits.ParameterTypeTuple and std.traits.ReturnType both exist in D1, if that's what you were worried about.
I think there may be a problem with 0-arg functions in the code? You handle the void return type (which I'm not sure is necessary actually -- I think D lets you say "return foo()" for a void function specifically to handle this kind of template situation), but I think maybe you don't handle a void argument? I'm getting an error with that for some reason... will dig more. --bb On Sat, Dec 13, 2008 at 5:54 AM, dsimcha <dsim...@yahoo.com> wrote: > == 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(); > } >