dmd v2.063.2 Hi there! I'm terribly hopeful that you're more interested in the problem at hand than my choice of title.
I've been using D for a while as my language of choice for various projects here and there, and I've recently discovered that template programming is magic. This is good. As part of the process of finding anything magic that also works, I've been going completely overboard with it. This involves, among other things, creating empty classes using templates and mixins at compile time, to build an inheritance hierarchy to do fancy things. This is all essentially irrelevant, but brings us to my issue. The next logical step in my adventure here was to see if I could create classes that weren't empty, but in fact has data members, generated at compile time using variadic templates. The first run-through went super well, and I was able to create classes with arbitrary primitive data types. However, ultimately I wanted these compile-time-generated classes with arbitrary data members to have data members that were of the type of the other classes that were also generated at compile time. That is to say, I want to generate, at compile time, classes like this: class MyClass { crazyTemplate!("MagicClassOne").MagicClassOne t1; crazyTemplate2!("MagicClassTwo").MagicClassTwo t2; } such that crazyTemplate and crazyTemplate2 each generate a class definition at compile time, accessible as defined by the string parameter. For example: template crazyTemplate(string classname) { mixin(`class ` ~ className ~ ` {}`); } The bare class-generating templates work, and generating classes that have arbitrary members at compile time using variadic templates given an arbitrary list of basic types works, but as soon as I try to use these template-generated classes as the types of the members of this variadic template, things go awry. I feel like what I'm trying to explain is a bit difficult to parse without a minimal working example, so here is one: code ------------- import std.stdio; import std.typetuple; import std.traits; import std.conv; class BaseClass {} template ChildT(string className) { mixin(`class ` ~ className ~ ` : BaseClass {}`); } template isChildOrBaseClass(T) { enum bool isChildOrBaseClass = is(T : BaseClass); } template GrabBagT(string className, T...) if (allSatisfy!(isChildOrBaseClass, T)) { mixin(genClassStr!(T)(className)); } string genClassStr(T...)(string className) { string classStr = ""; classStr ~= `static class ` ~ className ~ ` : BaseClass`; classStr ~= `{`; // Demonstrate that the template itself is not the problem classStr ~= ` ChildT!("BestChild").BestChild t1000;`; // Add arbitrary data members foreach (i, TI; T) { // Neither of these work with the generated classes, but the first // will work if GrabBagT is called with primitive types and its // constraint is commented out //classStr ~= fullyQualifiedName!(TI) ~ ` t` ~ to!(string)(i) ~ `;`; //classStr ~= __traits(identifier, TI) ~ ` t` ~ to!(string)(i) ~ `;`; } classStr ~= ` void printAttempts() {`; foreach (i, TI; T) { classStr ~= ` writeln(` ~ to!string(i) ~ `);`; } classStr ~= ` }`; classStr ~= `}`; return classStr; } int main(string[] args) { alias ChildT!("WorstChild").WorstChild WorstChild; alias ChildT!("MiddleChild").MiddleChild MiddleChild; auto magicObject = new GrabBagT!( "MagicClass", WorstChild, MiddleChild).MagicClass(); //auto magicObject = new GrabBagT!( // "MagicClass", int, float).MagicClass(); magicObject.printAttempts(); return 0; } ------------- That should compile and print out "0" and "1". Note the template constraint that bars the template instantiator from trying to instantiate GrabBagT with anything other than types that can be implicitly treated as type BaseClass. I tried using __traits(identifier) and fullyQualifiedName to get the actual type of the alias passed in (like the BestChild declaration), but the latter gives a mangled name, and the former gives just whatever the bare alias was. In any case. If the fullyQualifiedName line is uncommented, the error is: ------------ classAttributeGen.d(22): Error: undefined identifier '__T6ChildTVAyaa10_576f7273744368696c64Z' classAttributeGen.d(22): Error: classAttributeGen.__T6ChildTVAyaa10_576f7273744368696c64Z.WorstChild is used as a type classAttributeGen.d(22): Error: undefined identifier '__T6ChildTVAyaa11_4d6964646c654368696c64Z' classAttributeGen.d(22): Error: classAttributeGen.__T6ChildTVAyaa11_4d6964646c654368696c64Z.MiddleChild is used as a type classAttributeGen.d(54): Error: template instance classAttributeGen.GrabBagT!("MagicClass", WorstChild, MiddleChild) error instantiating ------------ If the __traits line is uncommented instead, the error is: ------------ classAttributeGen.d(22): Error: undefined identifier WorstChild classAttributeGen.d(22): Error: undefined identifier MiddleChild classAttributeGen.d(54): Error: template instance classAttributeGen.GrabBagT!("MagicClass", WorstChild, MiddleChild) error instantiating ------------ Of particular note is that we are giving the class a ChildT!("BestChild").BestChild member, which shows that simply using the empty-class-generating-templates is not the problem, but rather the way the type tuple is fed in to the variadic template. If the GrabBagT constraint is commented out, the uncommented magicObject instantiation is commented, the commented magicObject instantiation is uncommented, and the fullyQualifiedName line is uncommented, then this will also compile, demonstrating that a tuple of primitive data types can be used to generate classes at compile time with arbitrary, primitive data members. Ultimately, the problem I am trying to solve is generating class definitions at compile time with arbitrary, templated data members. If this is the wrong way to do it, by all means point me in the right direction. However, as an exercise to the community, is it even possible to do it the way I'm attempting here? Is it possible to do at all? Is there something awful about how templates are passed around that makes it fundamentally impossible to get their underlying type information, like with the working BestClass member, if they're passed in as template type parameters? If what I am asking is unclear, I will be more than happy to explain in a different way. I tried to be simultaneously as succinct and as comprehensive as possible with what the issue is. I also tried to find the answer to this problem, as I have with every other problem I've faced with D, through an exhaustive search of the various resources available to us, but alas I could find nothing. Of course, this is a fairly esoteric scenario, so that's entirely acceptable. That said, ideally the definitive answer can be found in future searches by finding this post. With a quiet but definitive stepping-aside to the inquiry of "What why are you doing this."