Template with template?
John Colvin
john.loughran.colvin at gmail.com
Thu Mar 20 13:20:26 PDT 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:
>> 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:
>>>> 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:
>>>>>> 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.
>>>>>
>>>>> Yep, I've already tried this (sorry I should've mentioned
>>>>> it!). But I don't want this restriction.
>>>>
>>>> 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.Variant
>>>
>>> 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.
>>
>> 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.
>
> 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.
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);
}
More information about the Digitalmars-d-learn
mailing list