1 module more.taggedunion;
2 
3 struct Tag
4 {
5     string name;
6     template opDispatch(string name)
7     {
8         enum opDispatch = Tag(name);
9     }
10 }
11 mixin template TaggedUnion(T...)
12 {
13     import std.conv : to;
14     private enum enumDefMixin =
15         "private enum TagEnum {\n" ~ function() {
16             string fields = "";
17             foreach (item; T)
18             {
19                 static if ( is(typeof(item) : Tag) )
20                 {
21                     fields ~= "    " ~ item.name ~ ",\n";
22                 }
23             }
24             return fields;
25         }() ~ "}\n";
26     pragma(msg, enumDefMixin);
27     mixin(enumDefMixin);
28 
29     private enum unionMixin =
30         "union {\n" ~ function() {
31             string result = "";
32             static foreach (itemIndex; 0 .. T.length)
33             {
34                 static if (itemIndex % 3 == 0)
35                 {
36                 }
37                 else static if (itemIndex % 3 == 1)
38                 {
39                     static if ( !is(T[itemIndex] == void))
40                     {
41                         result ~= "        T[" ~ itemIndex.to!string ~ "] ";
42                     }
43                 }
44                 else
45                 {
46                    static if (T[itemIndex] !is null)
47                    {
48                         result ~= T[itemIndex] ~ ";\n";
49                    }
50                 }
51             }
52             return result;
53         }() ~ "}\n";
54     pragma(msg, unionMixin);
55     mixin(unionMixin);
56     TagEnum tag;
57 }
58 unittest
59 {
60     struct PassOrFail
61     {
62         mixin TaggedUnion!(
63             Tag.pass, void, null,
64             Tag.fail, int, "errorCode");
65     }
66     auto result = PassOrFail();
67 }