Last update February 21, 2007

Doc Comments /
Template



Templates    

Table of contents of this page
Templates   
Messages   
struct template   
Template Linker Problem   
Kludgy Solution to Linker Problem   
An slightly better soloution (using a mixin)   
How does D handle non-deduced contexts?   
Limitations   
Links   

Messages    

Add your comments here...

struct template    

Apparently, a struct template can be declared in a similar fashion to how a class template can be declared. This suggested content is designed to explain this behavior.

  StructTemplateDeclaration:
    struct Identifier ( TemplateParameterList ) { DeclDefs }
If a template declares exactly one member, and that member is a struct with the same name as the template:
 template Bar(T)
 {
    struct Bar
    {
       T member;
    }
 }
then the semantic equivalent, called a StructTemplateDeclaration can be written as:
 struct Bar(T)
 {
    T member;
 }
Inspired by: NG:digitalmars.D/3895

Template Linker Problem    

I have a library with one template function in it

 template array_case(T)
 {
    void array_change_key_case ( T[ char [] ] map)
    {
       foreach ( inout char [] keys;map.keys )
       {
          keys = std.string.tolower(keys );
       }
    }
 }

However when I build the lib, I get the error
 Symbol Undefined _D3phd5array13array_case_Aa21array_change_key_caseFHAaAaZv
If i eliminate the template and just make them functions it works fine.

Source: NG:digitalmars.D.learn/1030

Kludgy Solution to Linker Problem    

The problem is that when templates are instantiated, they are inserted into an object file record called a COMDAT. COMDATs have the necessary feature that if multiple object files have a COMDAT with the same name, the duplicates are discarded.

This feature is necessary for template instantiations, since the compiler compiling one module doesn't know about the same templates being instantiated by another module.

An unfortunate side effect is that the one cannot pull object files out of a library by referencing COMDATs alone, one must reference something else in that object file, too.

The dmdscript.lib library (part of DMDScript) has the same problem with protoerror.d. I solved it with the kludge of inserting:

    int foo;
into the file, and then referencing it in dobject.d with:
    int* pfoo = &dmdscript.protoerror.foo;
Not too pretty, but it works.

Based on: NG:digitalmars.D/23701

An slightly better soloution (using a mixin)    

 int comdatKludge = 0;
 template kludge ()
 {
    int * kludge = &comdatKludge;
 }

into the library, then the client just calls

 mixin kludge;

Source: NG:digitalmars.D.learn/1034

How does D handle non-deduced contexts?    

Does D have the same problem as C++ w.r.t. non-deduced contexts, as described in section 14.8.2.4p4 of the c++ standard and as discussed in the following thread: http://groups.google.com/group/comp.lang.c++.moderated/msg/2cb76b2c61eb37ae ?

Limitations    

Templates cannot be used to add non-static members or functions to classes. This limitation is either outdated or the compiler doesn't properly check this case. The given sample compiles without any warning/error.

import std.stdio;

class TmplMeth
{
	int x;

	this (int y)
	{
		x = y;
		writefln("new TmplMeth:  this = %#.8x  new x = %d", cast(uint)cast(void*)this, x);
	}

	template method (T)
	{
	void method (int y)
	{
		writef("%#.8x.method!(%s):  old x = %d", cast(uint)cast(void*)this, typeid(T), x);
		x = y;
		writefln("  new x = %d", x);
	} }
}

void main ()
{
	TmplMeth tm = new TmplMeth(1);

	tm.method!(int)(2);
	tm.method!(char[])(3);
}

I think this is a new feature because if you look at the assembly code the implicit 'this' reference/pointer is definitely intentionally being passed:

_Dmain:
                push    EBP
                mov     EBP,ESP
                sub     ESP,4
                push    1
                mov     EAX,offset FLAT:_Class_8membtmpl8TmplMeth
                push    EAX
                call    near ptr _d_newclass
                ;; 'this' pointer of new TmplMeth Object is now in EAX
                add     ESP,4
                ;; constructor expects and gets 'this' pointer in EAX
                call    near ptr _D8membtmpl8TmplMeth5_ctorFiZC8membtmpl8TmplMeth
                ;; ctor expected to return 'this' in EAX, move it to _Dmain's local 'tm' variable
                mov     -4[EBP],EAX
                push    2
                ;; 'tm.method!(int)(2)' call, gets implicit 'this' still in EAX
                call    near ptr _D8membtmpl8TmplMeth8method_i6methodFiZv
                push    3
                ;; intentionally make sure 'tm' / 'this' is in EAX for next call
                mov     EAX,-4[EBP]
                ;; 'tm.method!(char[])(3)' call
                call    near ptr _D8membtmpl8TmplMeth9method_Aa6methodFiZv
                leave
                ret
                nop
                nop
                nop
.gnu.linkonce.t_Dmain   ends

;; TmplMeth.method!(int) instantiation:
_D8membtmpl8TmplMeth8method_i6methodFiZv:
                push    EBP
                mov     EBP,ESP
                sub     ESP,8
                push    EBX
                push    ESI
                ;; implicit 'this' expected in EAX, save it as a local variable
                mov     -4[EBP],EAX
                ;; try the non-existent invariant for some reason, with 'this' in EAX
                call    near ptr _D9invariant12_d_invariantFC6ObjectZv
                ;; make sure 'this' is still in EAX, indicates intentional feature
                mov     EAX,-4[EBP]
                ;; move pointer to 'this.x' into ECX, indicates intentional use of implicit 'this'
                lea     ECX,8[EAX]
                ;; push value of 'this.x' onto stack for 'writef' call
                push    dword ptr [ECX]
                ;; push reference to 'typeid(int)'
                mov     EDX,offset FLAT:_init_10TypeInfo_i
                push    EDX
                ;; push 'this' reference for 'writef', indicates intentional feature 
                push    dword ptr -4[EBP]
                ;; push the rest of the 'writef' variadic arguments
                push    dword ptr _TMP2[0Fh]
                push    dword ptr _TMP2[011h]
                push    dword ptr _arguments_AakC8TypeInfoi[04h]
                push    dword ptr _arguments_AakC8TypeInfoi
                ;; save 'this.x' pointer before 'writef' call, indicates intentional feature
                mov     -8[EBP],ECX
                call    near ptr _D3std5stdio6writefFYv
                ;; move 'method' parameter 'int y' value into EBX' 
                mov     EBX,8[EBP]
                ;; move saved 'this.x' pointer into ESI, indicates intentional feature
                mov     ESI,-8[EBP]
                ;; 'x = y', move 'y' value into location of 'this.x', intentional use of implicit 'this'
                mov     [ESI],EBX
                ;; push new 'this.x' for 'writefln' call, use EBX / 'y' because we know it's the same,
                ;; indicates intentional feature
                push    EBX
                push    dword ptr _TMP4[010h]
                push    dword ptr _TMP4[012h]
                push    dword ptr _arguments_Aai[04h]
                push    dword ptr _arguments_Aai
                call    near ptr _D3std5stdio8writeflnFYv
                add     ESP,030h
                pop     ESI
                pop     EBX
                leave
                ret     4
.gnu.linkonce.t_D8membtmpl8TmplMeth8method_i6methodFiZv ends

;; TmplMeth.method!(char[]) instantiation:
_D8membtmpl8TmplMeth9method_Aa6methodFiZv:
                Has the same intentional expectation and use of implicit 'this'.

Links    


FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: February 21, 2007 21:44 (diff))