/* C++ Templates - compiles with -std=c++98 Strengths of C++ templates: Templates are instantiated at compile time. A separate instance of the template is created for each instantiation at compile time. There is thus *no runtime overhead* for using templates. C++ templates not only generalize over types but also over constants, including functions and even other templates. Weaknesses of C++ templates: Templates are not type-checked until they're instantiated (see the `dontcallme` function below). Although wrong instantiations still result in compiler errors, "static typing" is weakened in the sense that you can define a template that works for some types but not others. The compiler will not verify that the template can be instantiated with any type. There is also (in 1998) no way to constrain the types and values that can instantiate a template. Creating a separate instance of the template for each instantiation can also result in redundant code generation, resulting in larger-than-necessary executables. */ #include #include using namespace std; template class list { public: T car; list *cdr; list(T a, list *b) {car=a; cdr=b;} int length() { int cx=0; for(list* i=this;i!=NULL;i=i->cdr) cx++; return cx; //return cx - car; // this will still compile! //return "abcd"; // compiles too: the template itself is not typechecked } // naturally polymorphic T largest() { T max = this->car; for(list i=this->cdr;i!=NULL;i=i->cdr) if (i->car > max) max=i->car; return max; //return max / car; // compiles for some instantiated types, not others } double dontcallme() { return "abc" / car; } //compiles if not called int dontevercallme(T x) { return x.washanddry("and wax too"); } }; // How to type check if a template is valid for all instantiations? // Instantiate it with an "arbitrary" type: class Arbitrary {}; int main() { // type checking template class and all its methods with arbitrary type: Arbitrary arbitrary; list* test = new list(arbitrary, NULL); //see if the instantiation compiles. cout << test->length() << endl; //cout << test->largest() << endl; // won't compile list *n = new list(3,NULL); list *m = new list(2.5,NULL); list *p = new list("abc",NULL); //p->largest(); Arbitrary *arb = new Arbitrary(); Arbitrary *arbi = new Arbitrary(); list *b = new list(arb,new list(arbi,NULL)); //cout << b->largest(); // only now do you get an error, // when you're writing a template class, how are you sure it won't get // instantiated with a type that it can't handle? return 0; }//main /* Original C++ templates is just a way for the compiler to create different versions of each class when instantiated. So the above main will actually create 4 copies of the class list. C++ does not try to type check expressions that include variables of generic type at compile time: It cannot check generic types, only the specific types once the template is instantiated. Unlike C# and Java, where you can constrain the range of type variables (where A:C, B extends Comparable). In reality, this is a just a way to automatically copy and paste. Also, naturally polymorphic functions such as the length function is neverthless duplicated, so there isn't really "one function" that works with different types. The most important practical consequence of C++ templates is that if you create a generic template library, say for a data structure on linked lists, the compiler cannot make any guaurantees of your code's type safety for all types that it may be applied to. */ /* Generated assembler code (g++ -S ) .file "templates.cpp" .local _ZSt8__ioinit .comm _ZSt8__ioinit,1,1 .text .align 2 .p2align 2,,3 .type _Z41__static_initialization_and_destruction_0ii, @function _Z41__static_initialization_and_destruction_0ii: .LFB1757: pushl %ebp .LCFI0: movl %esp, %ebp .LCFI1: subl $8, %esp .LCFI2: cmpl $65535, 12(%ebp) je .L3 .L1: leave ret .p2align 2,,3 .L3: cmpl $1, 8(%ebp) jne .L1 subl $12, %esp pushl $_ZSt8__ioinit .LCFI3: call _ZNSt8ios_base4InitC1Ev addl $12, %esp pushl $__dso_handle pushl $0 pushl $__tcf_0 call __cxa_atexit addl $16, %esp jmp .L1 .LFE1757: .size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii .globl _Unwind_Resume .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "abc" .LC1: .string "def" .text .align 2 .p2align 2,,3 .globl main .type main, @function main: .LFB1758: pushl %ebp .LCFI4: movl %esp, %ebp .LCFI5: pushl %edi .LCFI6: pushl %esi .LCFI7: pushl %ebx .LCFI8: subl $108, %esp .LCFI9: andl $-16, %esp subl $12, %esp pushl $8 .LEHB0: .LCFI10: call _Znwj .LEHE0: movl %eax, %edi movl $8, (%esp) .LEHB1: call _Znwj .LEHE1: movl %eax, %ebx movl $8, (%esp) .LEHB2: call _Znwj .LEHE2: .L20: .L8: .L22: movl $6, (%eax) movl $0, 4(%eax) movl $4, (%ebx) movl %eax, 4(%ebx) movl $2, (%edi) movl %ebx, 4(%edi) movl $8, (%esp) .LEHB3: call _Znwj .LEHE3: addl $12, %esp leal -56(%ebp), %edx pushl %edx pushl $.LC0 leal -40(%ebp), %esi pushl %esi movl %eax, -108(%ebp) .LEHB4: call _ZNSsC1EPKcRKSaIcE .LEHE4: movl $8, (%esp) .LEHB5: call _Znwj .LEHE5: .L25: addl $12, %esp leal -88(%ebp), %edx pushl %edx pushl $.LC1 leal -72(%ebp), %ebx pushl %ebx movl %eax, -112(%ebp) movb $1, -113(%ebp) .LEHB6: call _ZNSsC1EPKcRKSaIcE .LEHE6: .L31: .L34: .L36: .L39: .L42: .L45: .L49: .L52: .L56: .L59: popl %eax popl %edx #APP lock; addl $1,_ZNSs20_S_empty_rep_storageE+8 #NO_APP movl -112(%ebp), %ecx movl $_ZNSs20_S_empty_rep_storageE+12, (%ecx) pushl %ebx pushl %ecx .LEHB7: call _ZNSs6assignERKSs .LEHE7: .L68: .L75: .L79: .L82: .L85: .L89: .L93: .L96: .L99: .L103: .L107: .L112: .L118: .L121: .L123: .L126: .L129: .L132: .L136: .L139: .L143: .L146: popl %ecx movl -112(%ebp), %eax popl %ebx movb $0, -113(%ebp) movl $0, 4(%eax) #APP lock; addl $1,_ZNSs20_S_empty_rep_storageE+8 #NO_APP movl -108(%ebp), %ebx movl $_ZNSs20_S_empty_rep_storageE+12, (%ebx) pushl %esi pushl %ebx .LEHB8: call _ZNSs6assignERKSs .LEHE8: .L256: movl -108(%ebp), %ecx movl -112(%ebp), %edx movl -72(%ebp), %eax movl %edx, 4(%ecx) addl $16, %esp leal -12(%eax), %ecx leal -104(%ebp), %ebx movl $-1, %esi #APP lock; xaddl %esi,-4(%eax) #NO_APP testl %esi, %esi jle .L493 .L321: .L374: movl -40(%ebp), %eax leal -12(%eax), %ecx movl $-1, %esi #APP lock; xaddl %esi,-4(%eax) #NO_APP testl %esi, %esi jle .L494 .L436: .L433: subl $12, %esp pushl $12 .LEHB9: call _Znwj .LEHE9: movl %eax, %ebx movl $12, (%esp) .LEHB10: call _Znwj .LEHE10: .L440: movl $0, (%eax) movl $1074003968, 4(%eax) movl $0, 8(%eax) movl $0, (%ebx) movl $1073217536, 4(%ebx) movl %eax, 8(%ebx) movl %edi, (%esp) call _Z6lengthIiEiP4cellIT_E movl _ZSt4cout, %esi movl -12(%esi), %ecx addl $_ZSt4cout+4, %ecx movl %eax, %edx movl 8(%ecx), %eax addl $16, %esp testb $64, %al jne .L451 testb $8, %al je .L450 .L451: subl $8, %esp pushl %edx pushl $_ZSt4cout .LEHB11: call _ZNSolsEm .L488: popl %esi popl %edx pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ pushl %eax call _ZNSolsEPFRSoS_E movl %ebx, (%esp) call _Z6lengthIdEiP4cellIT_E movl _ZSt4cout, %esi movl -12(%esi), %ecx addl $_ZSt4cout+4, %ecx movl %eax, %edx movl 8(%ecx), %eax addl $16, %esp testb $64, %al jne .L459 testb $8, %al je .L458 .L459: subl $8, %esp pushl %edx pushl $_ZSt4cout call _ZNSolsEm .L489: popl %edx popl %ecx pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ pushl %eax call _ZNSolsEPFRSoS_E popl %esi pushl -108(%ebp) call _Z6lengthISsEiP4cellIT_E movl _ZSt4cout, %esi movl -12(%esi), %ecx addl $_ZSt4cout+4, %ecx movl %eax, %edx movl 8(%ecx), %eax addl $16, %esp testb $64, %al jne .L467 testb $8, %al je .L466 .L467: subl $8, %esp pushl %edx pushl $_ZSt4cout call _ZNSolsEm .L490: popl %edx popl %ecx pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ pushl %eax call _ZNSolsEPFRSoS_E movl %edi, (%esp) call _Z6suboneIiEvP4cellIT_E movl %ebx, (%esp) call _Z6suboneIdEvP4cellIT_E leal -12(%ebp), %esp popl %ebx popl %esi xorl %eax, %eax popl %edi leave ret .L466: subl $8, %esp pushl %edx pushl $_ZSt4cout call _ZNSolsEl jmp .L490 .L458: subl $8, %esp pushl %edx pushl $_ZSt4cout call _ZNSolsEl jmp .L489 .L450: subl $8, %esp pushl %edx pushl $_ZSt4cout call _ZNSolsEl jmp .L488 .L494: .L381: .L385: .L388: .L391: .L395: .L399: .L402: .L405: .L409: .L413: subl $8, %esp pushl %ebx pushl %ecx call _ZNSs4_Rep10_M_destroyERKSaIcE addl $16, %esp jmp .L433 .L493: .L263: .L267: .L270: .L273: .L277: .L281: .L284: .L287: .L291: .L295: subl $8, %esp pushl %ebx pushl %ecx call _ZNSs4_Rep10_M_destroyERKSaIcE addl $16, %esp jmp .L321 .p2align 2,,3 .L481: .L10: .L14: subl $12, %esp pushl %ebx movl %eax, %esi call _ZdlPv addl $16, %esp .L16: subl $12, %esp pushl %edi .L491: .L446: call _ZdlPv movl %esi, (%esp) call _Unwind_Resume .LEHE11: .p2align 2,,3 .L482: movl %eax, %esi jmp .L16 .L474: .L63: movl %eax, %esi movl -112(%ebp), %eax .L492: .L155: movl (%eax), %edx leal -12(%edx), %ecx leal -104(%ebp), %ebx movl $-1, %edi #APP lock; xaddl %edi,-4(%edx) #NO_APP testl %edi, %edi jle .L495 .L162: .L166: .L169: .L172: .L176: .L180: .L183: .L186: .L190: .L194: .L199: .L475: .L202: .L207: movl -72(%ebp), %eax leal -12(%eax), %ecx movl $-1, %edi #APP lock; xaddl %edi,-4(%eax) #NO_APP testl %edi, %edi jle .L496 .L311: .L477: .L300: .L304: .L307: .L314: cmpb $0, -113(%ebp) jne .L497 .p2align 2,,3 .L320: .L325: movl -40(%ebp), %eax leal -12(%eax), %ecx movl $-1, %edi #APP lock; xaddl %edi,-4(%eax) #NO_APP testl %edi, %edi jle .L498 .L429: .L480: .L418: .L422: .L425: .L432: subl $12, %esp pushl -108(%ebp) jmp .L491 .L498: .L332: .L336: .L339: .L342: .L346: .L350: .L353: .L356: .L360: .L364: .L369: subl $8, %esp pushl %ebx pushl %ecx call _ZNSs4_Rep10_M_destroyERKSaIcE addl $16, %esp jmp .L418 .L497: .L318: subl $12, %esp pushl -112(%ebp) call _ZdlPv addl $16, %esp jmp .L320 .L496: .L214: .L218: .L221: .L224: .L228: .L232: .L235: .L238: .L242: .L246: .L251: subl $8, %esp pushl %ebx pushl %ecx call _ZNSs4_Rep10_M_destroyERKSaIcE addl $16, %esp jmp .L300 .L495: subl $8, %esp pushl %ebx pushl %ecx call _ZNSs4_Rep10_M_destroyERKSaIcE addl $16, %esp jmp .L202 .L473: .L150: movl %eax, %esi movl -108(%ebp), %eax jmp .L492 .L476: movl %eax, %esi leal -104(%ebp), %ebx jmp .L300 .L478: movl %eax, %esi leal -104(%ebp), %ebx jmp .L320 .p2align 2,,3 .L479: movl %eax, %esi jmp .L418 .L472: .L442: subl $12, %esp movl %eax, %esi pushl %ebx jmp .L491 .LFE1758: .size main, .-main .section .gcc_except_table,"a",@progbits .LLSDA1758: .byte 0xff .byte 0xff .byte 0x1 .uleb128 .LLSDACSE1758-.LLSDACSB1758 .LLSDACSB1758: .uleb128 .LEHB0-.LFB1758 .uleb128 .LEHE0-.LEHB0 .uleb128 0x0 .uleb128 0x0 .uleb128 .LEHB1-.LFB1758 .uleb128 .LEHE1-.LEHB1 .uleb128 .L482-.LFB1758 .uleb128 0x0 .uleb128 .LEHB2-.LFB1758 .uleb128 .LEHE2-.LEHB2 .uleb128 .L481-.LFB1758 .uleb128 0x0 .uleb128 .LEHB3-.LFB1758 .uleb128 .LEHE3-.LEHB3 .uleb128 0x0 .uleb128 0x0 .uleb128 .LEHB4-.LFB1758 .uleb128 .LEHE4-.LEHB4 .uleb128 .L479-.LFB1758 .uleb128 0x0 .uleb128 .LEHB5-.LFB1758 .uleb128 .LEHE5-.LEHB5 .uleb128 .L478-.LFB1758 .uleb128 0x0 .uleb128 .LEHB6-.LFB1758 .uleb128 .LEHE6-.LEHB6 .uleb128 .L476-.LFB1758 .uleb128 0x0 .uleb128 .LEHB7-.LFB1758 .uleb128 .LEHE7-.LEHB7 .uleb128 .L474-.LFB1758 .uleb128 0x0 .uleb128 .LEHB8-.LFB1758 .uleb128 .LEHE8-.LEHB8 .uleb128 .L473-.LFB1758 .uleb128 0x0 .uleb128 .LEHB9-.LFB1758 .uleb128 .LEHE9-.LEHB9 .uleb128 0x0 .uleb128 0x0 .uleb128 .LEHB10-.LFB1758 .uleb128 .LEHE10-.LEHB10 .uleb128 .L472-.LFB1758 .uleb128 0x0 .uleb128 .LEHB11-.LFB1758 .uleb128 .LEHE11-.LEHB11 .uleb128 0x0 .uleb128 0x0 .LLSDACSE1758: .text .section .gnu.linkonce.t._Z6lengthIiEiP4cellIT_E,"ax",@progbits .align 2 .p2align 2,,3 .weak _Z6lengthIiEiP4cellIT_E .type _Z6lengthIiEiP4cellIT_E, @function _Z6lengthIiEiP4cellIT_E: .LFB1759: pushl %ebp .LCFI11: movl %esp, %ebp .LCFI12: movl 8(%ebp), %edx xorl %eax, %eax testl %edx, %edx je .L505 .p2align 2,,3 .L503: movl 4(%edx), %edx incl %eax testl %edx, %edx jne .L503 .L505: leave ret .LFE1759: .size _Z6lengthIiEiP4cellIT_E, .-_Z6lengthIiEiP4cellIT_E .section .gnu.linkonce.t._Z6lengthIdEiP4cellIT_E,"ax",@progbits .align 2 .p2align 2,,3 .weak _Z6lengthIdEiP4cellIT_E .type _Z6lengthIdEiP4cellIT_E, @function _Z6lengthIdEiP4cellIT_E: .LFB1760: pushl %ebp .LCFI13: movl %esp, %ebp .LCFI14: movl 8(%ebp), %edx xorl %eax, %eax testl %edx, %edx je .L512 .p2align 2,,3 .L510: movl 8(%edx), %edx incl %eax testl %edx, %edx jne .L510 .L512: leave ret .LFE1760: .size _Z6lengthIdEiP4cellIT_E, .-_Z6lengthIdEiP4cellIT_E .section .gnu.linkonce.t._Z6lengthISsEiP4cellIT_E,"ax",@progbits .align 2 .p2align 2,,3 .weak _Z6lengthISsEiP4cellIT_E .type _Z6lengthISsEiP4cellIT_E, @function _Z6lengthISsEiP4cellIT_E: .LFB1761: pushl %ebp .LCFI15: movl %esp, %ebp .LCFI16: movl 8(%ebp), %edx xorl %eax, %eax testl %edx, %edx je .L519 .p2align 2,,3 .L517: movl 4(%edx), %edx incl %eax testl %edx, %edx jne .L517 .L519: leave ret .LFE1761: .size _Z6lengthISsEiP4cellIT_E, .-_Z6lengthISsEiP4cellIT_E .section .gnu.linkonce.t._Z6suboneIiEvP4cellIT_E,"ax",@progbits .align 2 .p2align 2,,3 .weak _Z6suboneIiEvP4cellIT_E .type _Z6suboneIiEvP4cellIT_E, @function _Z6suboneIiEvP4cellIT_E: .LFB1762: pushl %ebp .LCFI17: movl %esp, %ebp .LCFI18: movl 8(%ebp), %ecx testl %ecx, %ecx movl %ecx, %eax je .L526 movl (%ecx), %edx .p2align 2,,3 .L524: movl 4(%eax), %eax decl %edx testl %eax, %eax jne .L524 movl %edx, (%ecx) .L526: leave ret .LFE1762: .size _Z6suboneIiEvP4cellIT_E, .-_Z6suboneIiEvP4cellIT_E .section .gnu.linkonce.t._Z6suboneIdEvP4cellIT_E,"ax",@progbits .align 2 .p2align 2,,3 .weak _Z6suboneIdEvP4cellIT_E .type _Z6suboneIdEvP4cellIT_E, @function _Z6suboneIdEvP4cellIT_E: .LFB1763: pushl %ebp .LCFI19: movl %esp, %ebp .LCFI20: movl 8(%ebp), %edx testl %edx, %edx movl %edx, %eax je .L534 fld1 fldl (%edx) .p2align 2,,3 .L532: movl 8(%eax), %eax testl %eax, %eax fsub %st(1), %st jne .L532 fstp %st(1) fstpl (%edx) .L534: leave ret .LFE1763: .size _Z6suboneIdEvP4cellIT_E, .-_Z6suboneIdEvP4cellIT_E .text .align 2 .p2align 2,,3 .type __tcf_0, @function __tcf_0: .LFB1764: pushl %ebp .LCFI21: movl %esp, %ebp .LCFI22: movl $_ZSt8__ioinit, 8(%ebp) leave .LCFI23: jmp _ZNSt8ios_base4InitD1Ev .LFE1764: .size __tcf_0, .-__tcf_0 .weak _ZNSt15basic_streambufIcSt11char_traitsIcEE13_S_pback_sizeE .section .gnu.linkonce.r._ZNSt15basic_streambufIcSt11char_traitsIcEE13_S_pback_sizeE,"a",@progbits .align 4 .type _ZNSt15basic_streambufIcSt11char_traitsIcEE13_S_pback_sizeE, @object .size _ZNSt15basic_streambufIcSt11char_traitsIcEE13_S_pback_sizeE, 4 _ZNSt15basic_streambufIcSt11char_traitsIcEE13_S_pback_sizeE: .long 1 .weak _ZNSt15basic_streambufIwSt11char_traitsIwEE13_S_pback_sizeE .section .gnu.linkonce.r._ZNSt15basic_streambufIwSt11char_traitsIwEE13_S_pback_sizeE,"a",@progbits .align 4 .type _ZNSt15basic_streambufIwSt11char_traitsIwEE13_S_pback_sizeE, @object .size _ZNSt15basic_streambufIwSt11char_traitsIwEE13_S_pback_sizeE, 4 _ZNSt15basic_streambufIwSt11char_traitsIwEE13_S_pback_sizeE: .long 1 .text .align 2 .p2align 2,,3 .type _GLOBAL__I_main, @function _GLOBAL__I_main: .LFB1766: pushl %ebp .LCFI24: movl %esp, %ebp .LCFI25: subl $16, %esp .LCFI26: pushl $65535 pushl $1 .LCFI27: call _Z41__static_initialization_and_destruction_0ii addl $16, %esp leave ret .LFE1766: .size _GLOBAL__I_main, .-_GLOBAL__I_main .section .ctors,"aw",@progbits .align 4 .long _GLOBAL__I_main .weak pthread_mutex_unlock .weak pthread_mutex_trylock .weak pthread_mutex_lock .weak pthread_create .weak pthread_setspecific .weak pthread_getspecific .weak pthread_key_delete .weak pthread_key_create .weak pthread_once .section .eh_frame,"a",@progbits .Lframe1: .long .LECIE1-.LSCIE1 .LSCIE1: .long 0x0 .byte 0x1 .string "zPL" .uleb128 0x1 .sleb128 -4 .byte 0x8 .uleb128 0x6 .byte 0x0 .long __gxx_personality_v0 .byte 0x0 .byte 0xc .uleb128 0x4 .uleb128 0x4 .byte 0x88 .uleb128 0x1 .align 4 .LECIE1: .LSFDE1: .long .LEFDE1-.LASFDE1 .LASFDE1: .long .LASFDE1-.Lframe1 .long .LFB1757 .long .LFE1757-.LFB1757 .uleb128 0x4 .long 0x0 .byte 0x4 .long .LCFI0-.LFB1757 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long .LCFI1-.LCFI0 .byte 0xd .uleb128 0x5 .byte 0x4 .long .LCFI3-.LCFI1 .byte 0x2e .uleb128 0x10 .align 4 .LEFDE1: .LSFDE3: .long .LEFDE3-.LASFDE3 .LASFDE3: .long .LASFDE3-.Lframe1 .long .LFB1758 .long .LFE1758-.LFB1758 .uleb128 0x4 .long .LLSDA1758 .byte 0x4 .long .LCFI4-.LFB1758 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long .LCFI5-.LCFI4 .byte 0xd .uleb128 0x5 .byte 0x4 .long .LCFI9-.LCFI5 .byte 0x83 .uleb128 0x5 .byte 0x86 .uleb128 0x4 .byte 0x87 .uleb128 0x3 .byte 0x4 .long .LCFI10-.LCFI9 .byte 0x2e .uleb128 0x10 .align 4 .LEFDE3: .LSFDE17: .long .LEFDE17-.LASFDE17 .LASFDE17: .long .LASFDE17-.Lframe1 .long .LFB1766 .long .LFE1766-.LFB1766 .uleb128 0x4 .long 0x0 .byte 0x4 .long .LCFI24-.LFB1766 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long .LCFI25-.LCFI24 .byte 0xd .uleb128 0x5 .byte 0x4 .long .LCFI27-.LCFI25 .byte 0x2e .uleb128 0x10 .align 4 .LEFDE17: .section .note.GNU-stack,"",@progbits .ident "GCC: (GNU) 3.3.3 20040412 (Red Hat Linux 3.3.3-7)" */