digitalmars.D.learn - Template with template?
- Chris (26/26) Mar 20 2014 How can I instantiate Person with Trait, i.e. a template with a
- Vladimir Panteleev (7/33) Mar 20 2014 Person!(Trait!(string, string)) person;
- Chris (4/43) Mar 20 2014 Yep, I've already tried this (sorry I should've mentioned it!).
- John Colvin (4/51) Mar 20 2014 Arrays are homogeneous. All the elements must be of the same
- Adam D. Ruppe (2/2) Mar 20 2014 Or make trait a class, storing the interface and passing the
- Chris (6/58) Mar 20 2014 The elements are all of type Trait. However, Type itself might be
- John Colvin (12/74) Mar 20 2014 Trait is not a type. Trait is a template. An instantiation of the
- Chris (16/91) Mar 20 2014 I thought the array T[] traits could hold any _type_ the template
- Philippe Sigaud (6/9) Mar 20 2014 Different instantiations of a template could become totally unrelated ty...
- Meta (25/28) Mar 20 2014 This is the best explanation for this restriction that I can
- John Colvin (42/139) Mar 20 2014 Try this:
- Chris (11/154) Mar 21 2014 Thanks John, this does what I had in mind. I don't know, though,
- Chris (3/167) Mar 21 2014 Btw, I was initially inspired by Objective-C's NSSet that can
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (3/5) Mar 23 2014 That's because Objective-C's objects are references. It would be
- Chris (3/9) Mar 24 2014 Yes, I will explore that too. Originally I thought I would have
- John Colvin (4/30) Mar 20 2014 templates can be passed to templates as alias parameters, or as
How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }
Mar 20 2014
On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 20 2014
On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev wrote:On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 20 2014
On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev wrote:Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.VariantOn Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 20 2014
Or make trait a class, storing the interface and passing the trait to the new Person in the constructor.
Mar 20 2014
On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev wrote:Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.VariantOn Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 20 2014
On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev wrote:Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.VariantOn Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 20 2014
On Thursday, 20 March 2014 at 18:54:30 UTC, John Colvin wrote:On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:I thought the array T[] traits could hold any _type_ the template Trait is instantiated into. That's where I got it wrong. I understand the practical aspects of this restriction (homogeneous data, performance and the work around involved etc.). However, this makes templates less universal and rather cumbersome to work with in certain circumstances. Take for example the Person class. If I want to do numerical operations with the age of the person, I will have to convert the age to an int (or whatever) later on instead of just doing it once at the beginning (when loading data). So everytime I access Trait.map["age"] I will have to convert it to a number before I can calculate anything. This, or I store it in a field of its own when instantiating Trait. Whatever workaround I choose it will make it less elegant and less simple. Maybe I expect(ed) to much of templates. Mea culpa.On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev wrote:Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.VariantOn Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 20 2014
Different instantiations of a template could become totally unrelated types (heck, even things that are *not* types: function definitions, values, code blocks, ...). So there is now way for an array could hold them all, in general. At their core, templates are just parameterized code blocks, that become whatever strikes your fancy.I thought the array T[] traits could hold any _type_ the template Trait is instantiated into.
Mar 20 2014
On Thursday, 20 March 2014 at 19:38:25 UTC, Chris wrote:I thought the array T[] traits could hold any _type_ the template Trait is instantiated into. That's where I got it wrong.This is the best explanation for this restriction that I can think of: struct Person(T) { static if (is(T == int)) { int age; property int age() { return age; } property int age(int val) { return age = val; } property bool isMiddleAge() { return age >= 30 && age <= 50); } } else static if (is(T == string)) { string name; //Etc... } } Depending on what type T is, Person could have an age and associated methods, or a name and associated methods, but never both. If T is neither int nor string, it will completely empty. Therefore, Person!int MUST be a completely different type from Person!string or Person!float. It just doesn't make any sense otherwise.
Mar 20 2014
On Thursday, 20 March 2014 at 19:38:25 UTC, Chris wrote:On Thursday, 20 March 2014 at 18:54:30 UTC, John Colvin wrote:Try this: import std.stdio; import std.variant; enum maxTraitSize = 64; struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; static assert(T0.sizeof + T1.sizeof + (T1[T0]).sizeof <= maxTraitSize); this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person { alias ElT = VariantN!maxTraitSize; ElT[] traits; void addTrait(T)(T trait) if(is(T == Trait!Q, Q...)) { traits ~= ElT(trait); } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln("%s", trait1.map); writefln("%s", trait2.map); auto p = new Person; p.addTrait(trait1); p.addTrait(trait2); writeln(p.traits); }On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:I thought the array T[] traits could hold any _type_ the template Trait is instantiated into. That's where I got it wrong. I understand the practical aspects of this restriction (homogeneous data, performance and the work around involved etc.). However, this makes templates less universal and rather cumbersome to work with in certain circumstances. Take for example the Person class. If I want to do numerical operations with the age of the person, I will have to convert the age to an int (or whatever) later on instead of just doing it once at the beginning (when loading data). So everytime I access Trait.map["age"] I will have to convert it to a number before I can calculate anything. This, or I store it in a field of its own when instantiating Trait. Whatever workaround I choose it will make it less elegant and less simple. Maybe I expect(ed) to much of templates. Mea culpa.On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev wrote:Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.VariantOn Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 20 2014
On Thursday, 20 March 2014 at 20:20:28 UTC, John Colvin wrote:On Thursday, 20 March 2014 at 19:38:25 UTC, Chris wrote:Thanks John, this does what I had in mind. I don't know, though, if I will use it for a real world application. I would have to test the behavior thoroughly first. The background is that I will have variable user input, i.e. users (non-programmers) define traits and rules. There is no way to foresee what names users will choose. That's why Trait stores arbitrary keys and values (and Meta's solution is not an option). I only thought it would be nice to have [string:int] straight away for numerical operations further down the road. I was also thinking about using std.variant. But I'm just starting out with this ...On Thursday, 20 March 2014 at 18:54:30 UTC, John Colvin wrote:Try this: import std.stdio; import std.variant; enum maxTraitSize = 64; struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; static assert(T0.sizeof + T1.sizeof + (T1[T0]).sizeof <= maxTraitSize); this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person { alias ElT = VariantN!maxTraitSize; ElT[] traits; void addTrait(T)(T trait) if(is(T == Trait!Q, Q...)) { traits ~= ElT(trait); } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln("%s", trait1.map); writefln("%s", trait2.map); auto p = new Person; p.addTrait(trait1); p.addTrait(trait2); writeln(p.traits); }On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:I thought the array T[] traits could hold any _type_ the template Trait is instantiated into. That's where I got it wrong. I understand the practical aspects of this restriction (homogeneous data, performance and the work around involved etc.). However, this makes templates less universal and rather cumbersome to work with in certain circumstances. Take for example the Person class. If I want to do numerical operations with the age of the person, I will have to convert the age to an int (or whatever) later on instead of just doing it once at the beginning (when loading data). So everytime I access Trait.map["age"] I will have to convert it to a number before I can calculate anything. This, or I store it in a field of its own when instantiating Trait. Whatever workaround I choose it will make it less elegant and less simple. Maybe I expect(ed) to much of templates. Mea culpa.On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev wrote:Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.VariantOn Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 21 2014
On Friday, 21 March 2014 at 09:54:24 UTC, Chris wrote:On Thursday, 20 March 2014 at 20:20:28 UTC, John Colvin wrote:Btw, I was initially inspired by Objective-C's NSSet that can hold arbitrary objects.On Thursday, 20 March 2014 at 19:38:25 UTC, Chris wrote:Thanks John, this does what I had in mind. I don't know, though, if I will use it for a real world application. I would have to test the behavior thoroughly first. The background is that I will have variable user input, i.e. users (non-programmers) define traits and rules. There is no way to foresee what names users will choose. That's why Trait stores arbitrary keys and values (and Meta's solution is not an option). I only thought it would be nice to have [string:int] straight away for numerical operations further down the road. I was also thinking about using std.variant. But I'm just starting out with this ...On Thursday, 20 March 2014 at 18:54:30 UTC, John Colvin wrote:Try this: import std.stdio; import std.variant; enum maxTraitSize = 64; struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; static assert(T0.sizeof + T1.sizeof + (T1[T0]).sizeof <= maxTraitSize); this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person { alias ElT = VariantN!maxTraitSize; ElT[] traits; void addTrait(T)(T trait) if(is(T == Trait!Q, Q...)) { traits ~= ElT(trait); } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln("%s", trait1.map); writefln("%s", trait2.map); auto p = new Person; p.addTrait(trait1); p.addTrait(trait2); writeln(p.traits); }On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:I thought the array T[] traits could hold any _type_ the template Trait is instantiated into. That's where I got it wrong. I understand the practical aspects of this restriction (homogeneous data, performance and the work around involved etc.). However, this makes templates less universal and rather cumbersome to work with in certain circumstances. Take for example the Person class. If I want to do numerical operations with the age of the person, I will have to convert the age to an int (or whatever) later on instead of just doing it once at the beginning (when loading data). So everytime I access Trait.map["age"] I will have to convert it to a number before I can calculate anything. This, or I store it in a field of its own when instantiating Trait. Whatever workaround I choose it will make it less elegant and less simple. Maybe I expect(ed) to much of templates. Mea culpa.On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev wrote:Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.VariantOn Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 21 2014
On Friday, 21 March 2014 at 09:56:49 UTC, Chris wrote:Btw, I was initially inspired by Objective-C's NSSet that can hold arbitrary objects.That's because Objective-C's objects are references. It would be equivalent to Adam Ruppe's suggestion of using classes/interfaces.
Mar 23 2014
On Sunday, 23 March 2014 at 12:37:34 UTC, Marc Schütz wrote:On Friday, 21 March 2014 at 09:56:49 UTC, Chris wrote:Yes, I will explore that too. Originally I thought I would have an array of references, but that was wrong of course.Btw, I was initially inspired by Objective-C's NSSet that can hold arbitrary objects.That's because Objective-C's objects are references. It would be equivalent to Adam Ruppe's suggestion of using classes/interfaces.
Mar 24 2014
On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:How can I instantiate Person with Trait, i.e. a template with a template? struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person(T) { T traits[]; void addTrait(T trait) { traits ~= trait; } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln(%s", trait1.map); writefln(%s", trait2.map); // above code compiles and works }templates can be passed to templates as alias parameters, or as part of a TemplateArgumentTuple. See http://dlang.org/template.html#aliasparameters
Mar 20 2014