import std.stdio; import std.metastrings; import std.typetuple; private template MixinMembers(int L, T, V...) { mixin(Format!("%s var%s;", T.stringof, L - 1 - V.length)); static if(V.length > 0) mixin MixinMembers!(L, V); } //catenate string at compile time.... private template MixinThisFunc(char[] S, T, V...) { public const char[] Result = S ~ Format!("public this(%s v) { assign!(%s)(v); } ", T.stringof, T.stringof); pragma(msg, Result ~ "\n"); static if(V.length > 0) mixin MixinThisFunc!(Result, V); } class Variant(TList...) { public alias TList TypeList; public alias Variant!(TList) SelfType; private union Holder { mixin MixinMembers!(TList.length, TList); } private Holder m_holder; private int m_which = -1; public mixin(MixinThisFunc!("",TypeList).Result); public this() { m_holder.var0 = m_holder.var0.init; m_which = 0; } public SelfType assign(T)(T rhs) { enum { index = IndexOf!(T, TypeList) } static assert( index >= 0); mixin(Format!("m_holder.var%s = rhs;", index)); m_which = index; return this; } public SelfType opAssign(T)(T rhs) { return assign(rhs); } public int which() { return m_which; } public T get(T)() { enum { index = IndexOf!(T, TypeList) } static assert(index >= 0); assert(index == which()); mixin(Format!("return m_holder.var%s;", index)); } } void main() { scope auto v = new Variant!(int, double, char, char[])(1000); writefln("which: %d", v.which()); v = 100.0; v = 'A'; writefln("which: %d", v.which()); char[] str = "foobar"; v = str; writefln("which: %d", v.which()); str = ""; str = v.get!(char[]); writefln(str); }