Automatic dynamic dispatch

Paulo Pinto pjmlp at progtools.org
Wed Feb 6 06:50:25 PST 2013


On Wednesday, 6 February 2013 at 04:37:17 UTC, Andrej Mitrovic 
wrote:
> Someone asked about how to invoke a function with the dynamic 
> type of
> an object. Essentially the user wanted to implement functions 
> external
> to a class without touching the class vtable (he might not have 
> access
> to it if it's in another library), but he explicitly wanted to 
> work on
> the derived type and not the base type, for example:
>
> class A { }
> class B : A { }
> class C : B { }
>
> void foo(B b) { }  // requires B or derived from B, not A
> void foo(C c) { }  // requires C or derived from C, not A
>
> Since all classes have a TypeInfo_Class associated with them, 
> we can
> create a few helper templates which figure out the entire class 
> tree
> from a set of leaf classes, and then tries to dynamically 
> dispatch to
> the appropriate function at runtime.
>
> Here's the code to do just that: http://dpaste.dzfl.pl/8338067b
>
> And pasted here for convenience:
>
> import std.stdio;
> import std.typetuple;
> import std.traits;
> import std.string;
>
> class A { }
> class B : A { }
> class C : B { }
> class D : B { }
>
> template ClassTreeImpl(Leaves...)
> {
>     static if (Leaves.length > 1)
>     {
>         alias TypeTuple!(Leaves[0], 
> BaseClassesTuple!(Leaves[0]),
>                          ClassTreeImpl!(Leaves[1..$])) 
> ClassTreeImpl;
>     }
>     else
>     static if (Leaves.length == 1)
>     {
>         alias TypeTuple!(Leaves[0], 
> BaseClassesTuple!(Leaves[0])) ClassTreeImpl;
>     }
>     else
>     {
>         alias TypeTuple!() ClassTreeImpl;
>     }
> }
>
> template ClassTree(Leaves...)
> {
>     alias 
> DerivedToFront!(NoDuplicates!(ClassTreeImpl!(Leaves))) 
> ClassTree;
> }
>
> void callFunc(alias func, Args...)(Args args)
>     if (Args.length >= 1 && is(Args[0] == class))
> {
>     auto objInfo = typeid(args[0]);
>     foreach (Base; ClassTree!(C, D))
>     {
>         if (objInfo == Base.classinfo)
>         {
>             static if (__traits(compiles,  // avoid CT errors 
> due to
> unrolled static foreach
>                 { return func(cast(Base)(cast(void*)args[0]),
> args[1..$]); }() ))
>             {
>                 return func(cast(Base)(cast(void*)args[0]), 
> args[1..$]);
>             }
>         }
>     }
>
>     assert(0, format("function '%s' is not callable with object 
> of
> dynamic type '%s'",
>                      __traits(identifier, func), 
> objInfo.toString()));
> }
>
> void foo(C c, int x) { writefln("foo(C) : received %s", x); }
> void foo(D d, int x, int y) { writefln("foo(D) : received %s 
> %s", x, y); }
>
> void main()
> {
>     A c = new C;
>     A d = new D;
>     A a = new A;
>
>     callFunc!foo(c, 1);    // ok
>     callFunc!foo(d, 2, 3); // ok
>     callFunc!foo(a, 3);    // will assert at runtime
> }
>
> It would have been a good blog entry, but I don't blog so.. :)

Wiki entry?



More information about the Digitalmars-d mailing list