CPlusPlus Templates The Complete Guide

569
T a b le o f C ontents C++ Templates: The Complete Guide B y D a v id V andevoorde , N i c o l a i M . J osuttis P u b l i s h e r : A d d i s o n W e s l e y P u b D a t e : N o v e m b e r 1 2, 20 0 2 I S B N : 0 -20 1 -7 3 4 8 4 -2 P a g e s : 5 5 2 T em p lates are am ong th e m os t p owerfu l featu res of C + + , bu t th ey are too often neg lected, m is u nders tood, and m i s u s ed. C++ Templates: The Complete Gu id e p rov i des s oftware arch i tects and eng i neers wi th a clear u nders tandi ng of wh y, wh en, and h ow to u s e tem p lates to bu i ld and m ai ntai n cleaner, fas ter, and s m arter s oftware m ore effi ci ently. C++ Templates beg i ns wi th an i ns ig h tfu l tu tori al on bas i c concep ts and lang u ag e featu res . T h e rem ai nder of th e book s erv es as a com p reh ens iv e reference, focu s i ng fi rs t on lang u ag e detai ls , th en on a wi de rang e of codi ng tech ni q u es , and fi nally on adv anced ap p li cati ons for tem p lates . E x am p les u s ed th rou g h ou t th e book i llu s trate abs tract concep ts and dem ons trate bes t p racti ces . R eaders learn T h e ex act beh av i ors of tem p lates H ow to av oi d th e p i tfalls as s oci ated wi th tem p lates I di om s and tech ni q u es , from th e bas i c to th e p rev i ou s ly u ndocu m ented H ow to reu s e s ou rce code wi th ou t th reateni ng p erform ance or s afety H ow to i ncreas e th e effi ci ency of C + + p rog ram s H ow to p rodu ce m ore flex i ble and m ai ntai nable s oftware

Transcript of CPlusPlus Templates The Complete Guide

Page 1: CPlusPlus Templates The Complete Guide

• T a b l e o f C o n t e n t s C++ Templates: The Complete Guide B y D a v i d V a n d e v o o r d e , N i c o l a i M . J o s u t t i s P u b l i s h e r : A d d i s o n W e s l e y P u b D a t e : N o v e m b e r 1 2, 20 0 2 I S B N : 0 -20 1 -7 3 4 8 4 -2 P a g e s : 5 5 2

T em p lates are am ong th e m os t p owerfu l featu res of C + + , bu t th ey are too often neg lected, m i s u nders tood, and m i s u s ed. C++ Templates: The Complete Gu i d e p rov i des s oftware arch i tects and eng i neers wi th a clear u nders tandi ng of wh y, wh en, and h ow to u s e tem p lates to bu i ld and m ai ntai n cleaner, fas ter, and s m arter s oftware m ore effi ci ently.

C++ Templates beg i ns wi th an i ns i g h tfu l tu tori al on bas i c concep ts and lang u ag e featu res . T h e rem ai nder of th e book s erv es as a com p reh ens i v e reference, focu s i ng fi rs t on lang u ag e detai ls , th en on a wi de rang e of codi ng tech ni q u es , and fi nally on adv anced ap p li cati ons for tem p lates . E x am p les u s ed th rou g h ou t th e book i llu s trate abs tract concep ts and dem ons trate bes t p racti ces .

R eaders learn

• T h e ex act beh av i ors of tem p lates • H ow to av oi d th e p i tfalls as s oci ated wi th tem p lates • I di om s and tech ni q u es , from th e bas i c to th e p rev i ou s ly u ndocu m ented • H ow to reu s e s ou rce code wi th ou t th reateni ng p erform ance or s afety • H ow to i ncreas e th e effi ci ency of C + + p rog ram s • H ow to p rodu ce m ore flex i ble and m ai ntai nable s oftware

Page 2: CPlusPlus Templates The Complete Guide

T h i s p racti cal g u i de s h ows p rog ram m ers h ow to ex p loi t th e fu ll p ower of th e tem p late featu res i n C + + .

Page 3: CPlusPlus Templates The Complete Guide

• T a b l e o f C o n t e n t s C++ Templates: The Complete Guide B y D a v i d V a n d e v o o r d e , N i c o l a i M . J o s u t t i s P u b l i s h e r : A d d i s o n W e s l e y P u b D a t e : N o v e m b e r 1 2, 20 0 2 I S B N : 0 -20 1 -7 3 4 8 4 -2 P a g e s : 5 5 2

C o p yr i g h t P r e f a c e A c k n o w l e d g m e n t s N i c o ' s A c k n o w l e d g m e n t s D a v i d ' s A c k n o w l e d g m e n t s C h a p t e r 1 . A b o u t T h i s B o o k S e c t i o n 1 .1 . W h a t Y o u S h o u l d K n o w B e f o r e R e a d i n g T h i s B o o k S e c t i o n 1 .2. O v e r a l l S t r u c t u r e o f t h e B o o k S e c t i o n 1 .3 . H o w t o R e a d T h i s B o o k S e c t i o n 1 .4 . S o m e R e m a r k s A b o u t P r o g r a m m i n g S t yl e S e c t i o n 1 .5 . T h e S t a n d a r d v e r s u s R e a l i t y S e c t i o n 1 .6 . E x a m p l e C o d e a n d A d d i t i o n a l I n f o r m a t i o n s S e c t i o n 1 .7 . F e e d b a c k P a r t I : T h e B a s i c s C h a p t e r 2. F u n c t i o n T e m p l a t e s S e c t i o n 2.1 . A F i r s t L o o k a t F u n c t i o n T e m p l a t e s S e c t i o n 2.2. A r g u m e n t D e d u c t i o n S e c t i o n 2.3 . T e m p l a t e P a r a m e t e r s

Page 4: CPlusPlus Templates The Complete Guide

S e c t i o n 2.4 . O v e r l o a d i n g F u n c t i o n T e m p l a t e s S e c t i o n 2.5 . S u m m a r y C h a p t e r 3 . C l a s s T e m p l a t e s S e c t i o n 3 .1 . I m p l e m e n t a t i o n o f C l a s s T e m p l a t e Stack S e c t i o n 3 .2. U s e o f C l a s s T e m p l a t e Stack S e c t i o n 3 .3 . S p e c i a l i z a t i o n s o f C l a s s T e m p l a t e s S e c t i o n 3 .4 . P a r t i a l S p e c i a l i z a t i o n S e c t i o n 3 .5 . D e f a u l t T e m p l a t e A r g u m e n t s S e c t i o n 3 .6 . S u m m a r y C h a p t e r 4 . N o n t yp e T e m p l a t e P a r a m e t e r s S e c t i o n 4 .1 . N o n t yp e C l a s s T e m p l a t e P a r a m e t e r s S e c t i o n 4 .2. N o n t yp e F u n c t i o n T e m p l a t e P a r a m e t e r s S e c t i o n 4 .3 . R e s t r i c t i o n s f o r N o n t yp e T e m p l a t e P a r a m e t e r s S e c t i o n 4 .4 . S u m m a r y C h a p t e r 5 . T r i c k y B a s i c s S e c t i o n 5 .1 . K e yw o r d typename S e c t i o n 5 .2. U s i n g this-> S e c t i o n 5 .3 . M e m b e r T e m p l a t e s S e c t i o n 5 .4 . T e m p l a t e T e m p l a t e P a r a m e t e r s S e c t i o n 5 .5 . Z e r o I n i t i a l i z a t i o n S e c t i o n 5 .6 . U s i n g S t r i n g L i t e r a l s a s A r g u m e n t s f o r F u n c t i o n T e m p l a t e s S e c t i o n 5 .7 . S u m m a r y C h a p t e r 6 . U s i n g T e m p l a t e s i n P r a c t i c e S e c t i o n 6 .1 . T h e I n c l u s i o n M o d e l S e c t i o n 6 .2. E x p l i c i t I n s t a n t i a t i o n S e c t i o n 6 .3 . T h e S e p a r a t i o n M o d e l S e c t i o n 6 .4 . T e m p l a t e s a n d inline S e c t i o n 6 .5 . P r e c o m p i l e d H e a d e r s S e c t i o n 6 .6 . D e b u g g i n g T e m p l a t e s S e c t i o n 6 .7 . A f t e r n o t e s S e c t i o n 6 .8 . S u m m a r y C h a p t e r 7 . B a s i c T e m p l a t e T e r m i n o l o g y S e c t i o n 7 .1 . " C l a s s T e m p l a t e " o r " T e m p l a t e C l a s s " ? S e c t i o n 7 .2. I n s t a n t i a t i o n a n d S p e c i a l i z a t i o n S e c t i o n 7 .3 . D e c l a r a t i o n s v e r s u s D e f i n i t i o n s S e c t i o n 7 .4 . T h e O n e -D e f i n i t i o n R u l e S e c t i o n 7 .5 . T e m p l a t e A r g u m e n t s v e r s u s T e m p l a t e P a r a m e t e r s

Page 5: CPlusPlus Templates The Complete Guide

P a r t I I : T e m p l a t e s i n D e p t h C h a p t e r 8 . F u n d a m e n t a l s i n D e p t h S e c t i o n 8 .1 . P a r a m e t e r i z e d D e c l a r a t i o n s S e c t i o n 8 .2. T e m p l a t e P a r a m e t e r s S e c t i o n 8 .3 . T e m p l a t e A r g u m e n t s S e c t i o n 8 .4 . F r i e n d s S e c t i o n 8 .5 . A f t e r n o t e s C h a p t e r 9 . N a m e s i n T e m p l a t e s S e c t i o n 9 .1 . N a m e T a x o n o m y S e c t i o n 9 .2. L o o k i n g U p N a m e s S e c t i o n 9 .3 . P a r s i n g T e m p l a t e s S e c t i o n 9 .4 . D e r i v a t i o n a n d C l a s s T e m p l a t e s S e c t i o n 9 .5 . A f t e r n o t e s C h a p t e r 1 0 . I n s t a n t i a t i o n S e c t i o n 1 0 .1 . O n -D e m a n d I n s t a n t i a t i o n S e c t i o n 1 0 .2. L a z y I n s t a n t i a t i o n S e c t i o n 1 0 .3 . T h e C + + I n s t a n t i a t i o n M o d e l S e c t i o n 1 0 .4 . I m p l e m e n t a t i o n S c h e m e s S e c t i o n 1 0 .5 . E x p l i c i t I n s t a n t i a t i o n S e c t i o n 1 0 .6 . A f t e r n o t e s C h a p t e r 1 1 . T e m p l a t e A r g u m e n t D e d u c t i o n S e c t i o n 1 1 .1 . T h e D e d u c t i o n P r o c e s s S e c t i o n 1 1 .2. D e d u c e d C o n t e x t s S e c t i o n 1 1 .3 . S p e c i a l D e d u c t i o n S i t u a t i o n s S e c t i o n 1 1 .4 . A l l o w a b l e A r g u m e n t C o n v e r s i o n s S e c t i o n 1 1 .5 . C l a s s T e m p l a t e P a r a m e t e r s S e c t i o n 1 1 .6 . D e f a u l t C a l l A r g u m e n t s S e c t i o n 1 1 .7 . T h e B a r t o n -N a c k m a n T r i c k S e c t i o n 1 1 .8 . A f t e r n o t e s C h a p t e r 1 2. S p e c i a l i z a t i o n a n d O v e r l o a d i n g S e c t i o n 1 2.1 . W h e n " G e n e r i c C o d e " D o e s n ' t Q u i t e C u t I t S e c t i o n 1 2.2. O v e r l o a d i n g F u n c t i o n T e m p l a t e s S e c t i o n 1 2.3 . E x p l i c i t S p e c i a l i z a t i o n S e c t i o n 1 2.4 . P a r t i a l C l a s s T e m p l a t e S p e c i a l i z a t i o n S e c t i o n 1 2.5 . A f t e r n o t e s C h a p t e r 1 3 . F u t u r e D i r e c t i o n s S e c t i o n 1 3 .1 . T h e A n g l e B r a c k e t H a c k

Page 6: CPlusPlus Templates The Complete Guide

S e c t i o n 1 3 .2. R e l a x e d typename R u l e s S e c t i o n 1 3 .3 . D e f a u l t F u n c t i o n T e m p l a t e A r g u m e n t s S e c t i o n 1 3 .4 . S t r i n g L i t e r a l a n d F l o a t i n g -P o i n t T e m p l a t e A r g u m e n t s S e c t i o n 1 3 .5 . R e l a x e d M a t c h i n g o f T e m p l a t e T e m p l a t e P a r a m e t e r s S e c t i o n 1 3 .6 . T yp e d e f T e m p l a t e s S e c t i o n 1 3 .7 . P a r t i a l S p e c i a l i z a t i o n o f F u n c t i o n T e m p l a t e s S e c t i o n 1 3 .8 . T h e typeof O p e r a t o r S e c t i o n 1 3 .9 . N a m e d T e m p l a t e A r g u m e n t s S e c t i o n 1 3 .1 0 . S t a t i c P r o p e r t i e s S e c t i o n 1 3 .1 1 . C u s t o m I n s t a n t i a t i o n D i a g n o s t i c s S e c t i o n 1 3 .1 2. O v e r l o a d e d C l a s s T e m p l a t e s S e c t i o n 1 3 .1 3 . L i s t P a r a m e t e r s S e c t i o n 1 3 .1 4 . L a yo u t C o n t r o l S e c t i o n 1 3 .1 5 . I n i t i a l i z e r D e d u c t i o n S e c t i o n 1 3 .1 6 . F u n c t i o n E x p r e s s i o n s S e c t i o n 1 3 .1 7 . A f t e r n o t e s P a r t I I I : T e m p l a t e s a n d D e s i g n C h a p t e r 1 4 . T h e P o l ym o r p h i c P o w e r o f T e m p l a t e s S e c t i o n 1 4 .1 . D yn a m i c P o l ym o r p h i s m S e c t i o n 1 4 .2. S t a t i c P o l ym o r p h i s m S e c t i o n 1 4 .3 . D yn a m i c v e r s u s S t a t i c P o l ym o r p h i s m 1 4 .4 N e w F o r m s o f D e s i g n P a t t e r n s S e c t i o n 1 4 .5 . G e n e r i c P r o g r a m m i n g S e c t i o n 1 4 .6 . A f t e r n o t e s C h a p t e r 1 5 . T r a i t s a n d P o l i c y C l a s s e s S e c t i o n 1 5 .1 . A n E x a m p l e : A c c u m u l a t i n g a S e q u e n c e S e c t i o n 1 5 .2. T yp e F u n c t i o n s S e c t i o n 1 5 .3 . P o l i c y T r a i t s S e c t i o n 1 5 .4 . A f t e r n o t e s C h a p t e r 1 6 . T e m p l a t e s a n d I n h e r i t a n c e S e c t i o n 1 6 .1 . N a m e d T e m p l a t e A r g u m e n t s S e c t i o n 1 6 .2. T h e E m p t y B a s e C l a s s O p t i m i z a t i o n ( E B C O ) S e c t i o n 1 6 .3 . T h e C u r i o u s l y R e c u r r i n g T e m p l a t e P a t t e r n ( C R T P ) S e c t i o n 1 6 .4 . P a r a m e t e r i z e d V i r t u a l i t y S e c t i o n 1 6 .5 . A f t e r n o t e s C h a p t e r 1 7 . M e t a p r o g r a m s S e c t i o n 1 7 .1 . A F i r s t E x a m p l e o f a M e t a p r o g r a m S e c t i o n 1 7 .2. E n u m e r a t i o n V a l u e s v e r s u s S t a t i c C o n s t a n t s

Page 7: CPlusPlus Templates The Complete Guide

S e c t i o n 1 7 .3 . A S e c o n d E x a m p l e : C o m p u t i n g t h e S q u a r e R o o t S e c t i o n 1 7 .4 . U s i n g I n d u c t i o n V a r i a b l e s S e c t i o n 1 7 .5 . C o m p u t a t i o n a l C o m p l e t e n e s s S e c t i o n 1 7 .6 . R e c u r s i v e I n s t a n t i a t i o n v e r s u s R e c u r s i v e T e m p l a t e A r g u m e n t s S e c t i o n 1 7 .7 . U s i n g M e t a p r o g r a m s t o U n r o l l L o o p s S e c t i o n 1 7 .8 . A f t e r n o t e s C h a p t e r 1 8 . E x p r e s s i o n T e m p l a t e s S e c t i o n 1 8 .1 . T e m p o r a r i e s a n d S p l i t L o o p s S e c t i o n 1 8 .2. E n c o d i n g E x p r e s s i o n s i n T e m p l a t e A r g u m e n t s S e c t i o n 1 8 .3 . P e r f o r m a n c e a n d L i m i t a t i o n s o f E x p r e s s i o n T e m p l a t e s S e c t i o n 1 8 .4 . A f t e r n o t e s P a r t I V : A d v a n c e d A p p l i c a t i o n s C h a p t e r 1 9 . T yp e C l a s s i f i c a t i o n S e c t i o n 1 9 .1 . D e t e r m i n i n g F u n d a m e n t a l T yp e s S e c t i o n 1 9 .2. D e t e r m i n i n g C o m p o u n d T yp e s S e c t i o n 1 9 .3 . I d e n t i f yi n g F u n c t i o n T yp e s S e c t i o n 1 9 .4 . E n u m e r a t i o n C l a s s i f i c a t i o n w i t h O v e r l o a d R e s o l u t i o n S e c t i o n 1 9 .5 . D e t e r m i n i n g C l a s s T yp e s S e c t i o n 1 9 .6 . P u t t i n g I t A l l T o g e t h e r S e c t i o n 1 9 .7 . A f t e r n o t e s C h a p t e r 20 . S m a r t P o i n t e r s S e c t i o n 20 .1 . H o l d e r s a n d T r u l e s S e c t i o n 20 .2. R e f e r e n c e C o u n t i n g S e c t i o n 20 .3 . A f t e r n o t e s C h a p t e r 21 . T u p l e s S e c t i o n 21 .1 . D u o s S e c t i o n 21 .2. R e c u r s i v e D u o s S e c t i o n 21 .3 . T u p l e C o n s t r u c t i o n S e c t i o n 21 .4 . A f t e r n o t e s C h a p t e r 22. F u n c t i o n O b j e c t s a n d C a l l b a c k s S e c t i o n 22.1 . D i r e c t , I n d i r e c t , a n d I n l i n e C a l l s S e c t i o n 22.2. P o i n t e r s a n d R e f e r e n c e s t o F u n c t i o n s S e c t i o n 22.3 . P o i n t e r -t o -M e m b e r F u n c t i o n s S e c t i o n 22.4 . C l a s s T yp e F u n c t o r s S e c t i o n 22.5 . S p e c i f yi n g F u n c t o r s S e c t i o n 22.6 . I n t r o s p e c t i o n S e c t i o n 22.7 . F u n c t i o n O b j e c t C o m p o s i t i o n

Page 8: CPlusPlus Templates The Complete Guide

S e c t i o n 22.8 . V a l u e B i n d e r s F u n c t o r O p e r a t i o n s : A C o m p l e t e I m p l e m e n t a t i o n S e c t i o n 22.1 0 . A f t e r n o t e s A p p e n d i x A . T h e O n e -D e f i n i t i o n R u l e S e c t i o n A .1 . T r a n s l a t i o n U n i t s S e c t i o n A .2. D e c l a r a t i o n s a n d D e f i n i t i o n s S e c t i o n A .3 . T h e O n e -D e f i n i t i o n R u l e i n D e t a i l A p p e n d i x B . O v e r l o a d R e s o l u t i o n S e c t i o n B .1 . W h e n D o e s O v e r l o a d R e s o l u t i o n K i c k I n ? S e c t i o n B .2. S i m p l i f i e d O v e r l o a d R e s o l u t i o n S e c t i o n B .3 . O v e r l o a d i n g D e t a i l s B i b l i o g r a p h y N e w s g r o u p s B o o k s a n d W e b S i t e s G l o s s a r y

Page 9: CPlusPlus Templates The Complete Guide

Copyright

M any of th e des i g nati ons u s ed by m anu factu rers and s ellers to di s ti ng u i s h th ei r p rodu cts are clai m ed as tradem ark s . W h ere th os e des i g nati ons ap p ear i n th i s book , and A ddi s on-W es ley was aware of a tradem ark clai m , th e des i g nati ons h av e been p ri nted wi th i ni ti al cap i tal letters or i n all cap i tals .

T h e au th ors and p u bli s h er h av e tak en care i n th e p rep arati on of th i s book , bu t m ak e no ex p res s ed or i m p li ed warranty of any k i nd and as s u m e no res p ons i bi li ty for errors or om i s s i ons . N o li abi li ty i s as s u m ed for i nci dental or cons eq u enti al dam ag es i n connecti on wi th or ari s i ng ou t of th e u s e of th e i nform ati on or p rog ram s contai ned h erei n.

T h e p u bli s h er offers di s cou nts on th i s book wh en ordered i n q u anti ty for s p eci al s ales . F or m ore i nform ati on, p leas e contact:

U .S. C orp orate and G ov ernm ent Sales

(8 00) 3 8 2-3 4 19

corp s ales @ p ears ontech g rou p .com

F or s ales ou ts i de of th e U ni ted States , p leas e contact:

I nternati onal Sales

(3 17 ) 5 8 1-3 7 9 3

i nternati onal@ p ears ontech g rou p .com

V i s i t A ddi s on-W es ley on th e W eb: www.awp rofes s i onal.com

L i b r ar y of Con g r ess Catalog i n g -i n -Pu b li c ati on D ata

V andev oorde, D av i d.

C + + tem p lates : th e com p lete g u i de / D av i d V andev oorde, N i colai M . J os u tti s .

p . cm .

I nclu des bi bli og rap h i cal references and i ndex .

Page 10: CPlusPlus Templates The Complete Guide

0-201-7 3 4 8 4 -2

1. M i cros oft V i s u al C + + . 2. C + + (C om p u ter p rog ram lang u ag e) 3 . Standard tem p late li brary. I . J os u tti s , N i colai M . I I . T i tle.

Q A 7 6.7 3 .C 15 3 V 3 7 2003

005 .26' 8 —dc21 2002027 9 3 3

C op yri g h t © 2003 by P ears on E du cati on, I nc.

A ll ri g h ts res erv ed. N o p art of th i s p u bli cati on m ay be rep rodu ced, s tored i n a retri ev al s ys tem , or trans m i tted, i n any form , or by any m eans , electroni c, m ech ani cal, p h otocop yi ng , recordi ng , or oth erwi s e, wi th ou t th e p ri or cons ent of th e p u bli s h er. P ri nted i n th e U ni ted States of A m eri ca. P u bli s h ed s i m u ltaneou s ly i n C anada.

F or i nform ati on on obtai ni ng p erm i s s i on for u s e of m ateri al from th i s work , p leas e s u bm i t a wri tten req u es t to:

P ears on E du cati on, I nc.

R i g h ts and C ontracts D ep artm ent

7 5 A rli ng ton Street, Su i te 3 00

B os ton, M A 02116

F ax : (617 ) 8 4 8 -7 04 7

T ex t p ri nted on recycled p ap er

1 2 3 4 5 6 7 8 9 10—M A —0605 04 03 02

F i rs t p ri nti ng , N ov em ber 2002

Dedication

To K ar i n a

—D av i d

To those w ho help an d lov e

—Ni c o

Page 11: CPlusPlus Templates The Complete Guide
Page 12: CPlusPlus Templates The Complete Guide

Preface

T h e i dea of tem p lates i n C + + i s m ore th an ten years old. C + + tem p lates were already docu m ented i n 19 9 0 i n th e " A nnotated C + + R eference M anu al" or s o-called " A R M " (s ee [E lli s Strou s tru p A R M ] ) and th ey h ad been des cri bed before th at i n m ore s p eci ali z ed p u bli cati ons . H owev er, well ov er a decade later we fou nd a dearth of li teratu re th at concentrates on th e fu ndam ental concep ts and adv anced tech ni q u es of th i s fas ci nati ng , com p lex , and p owerfu l C + + featu re. W e wanted to addres s th i s i s s u e and deci ded to wri te the book abou t tem p lates (wi th p erh ap s a s li g h t lack of h u m i li ty).

H owev er, we ap p roach ed th e tas k wi th di fferent back g rou nds and wi th di fferent i ntenti ons . D av i d, an ex p eri enced com p i ler i m p lem enter and m em ber of th e C + + Standard C om m i ttee C ore L ang u ag e W ork i ng G rou p , was i nteres ted i n an ex act and detai led des cri p ti on of all th e p ower (and p roblem s ) of tem p lates . N i co, an " ordi nary" ap p li cati on p rog ram m er and m em ber of th e C + + Standard C om m i ttee L i brary W ork i ng G rou p , was i nteres ted i n u nders tandi ng all th e tech ni q u es of tem p lates i n a way th at h e cou ld u s e and benefi t from th em . I n addi ti on, we both wanted to s h are th i s k nowledg e wi th you , th e reader, and th e wh ole com m u ni ty to h elp to av oi d fu rth er m i s u nders tandi ng , confu s i on, or ap p reh ens i on.

A s a cons eq u ence, you wi ll s ee both concep tu al i ntrodu cti ons wi th day-to-day ex am p les and detai led des cri p ti ons of th e ex act beh av i or of tem p lates . Starti ng from th e bas i c p ri nci p les of tem p lates and work i ng u p to th e " art of tem p late p rog ram m i ng , " you wi ll di s cov er (or redi s cov er) tech ni q u es s u ch as s tati c p olym orp h i s m , p oli cy clas s es , m etap rog ram m i ng , and ex p res s i on tem p lates . Y ou wi ll als o g ai n a deep er u nders tandi ng of th e C + + s tandard li brary, i n wh i ch alm os t all code i nv olv es tem p lates .

W e learned a lot and we h ad m u ch fu n wh i le wri ti ng th i s book . W e h op e you wi ll h av e th e s am e ex p eri ence wh i le readi ng i t. E nj oy!

Page 13: CPlusPlus Templates The Complete Guide

Acknowledgments

T h i s book p res ents i deas , concep ts , s olu ti ons , and ex am p les from m any s ou rces . W e' d li k e to th ank all th e p eop le and com p ani es wh o h elp ed and s u p p orted u s du ri ng th e p as t few years .

F i rs t, we' d li k e to th ank all th e rev i ewers and ev eryone els e wh o g av e u s th ei r op i ni on on early m anu s cri p ts . T h es e p eop le endow th e book wi th a q u ali ty i t wou ld nev er h av e h ad wi th ou t th ei r i np u t. T h e rev i ewers for th i s book were K yle B laney, T h om as G s ch wi nd, D enni s M ancl, P atri ck M c K i llen, and J an C h ri s ti aan v an W i nk el. Sp eci al th ank s to D i etm ar K ü h l, wh o m eti cu lou s ly rev i ewed and edi ted th e wh ole book . H i s feedback was an i ncredi ble contri bu ti on to th e q u ali ty of th i s book .

W e' d als o li k e to th ank all th e p eop le and com p ani es wh o g av e u s th e op p ortu ni ty to tes t ou r ex am p les on di fferent p latform s wi th di fferent com p i lers . M any th ank s to th e E di s on D es i g n G rou p for th ei r g reat com p i ler and th ei r s u p p ort. I t was a bi g h elp du ri ng th e s tandardi z ati on p roces s and th e wri ti ng of th i s book . M any th ank s als o g o to all th e dev elop ers of th e free G N U and eg cs com p i lers (J as on M erri ll was es p eci ally res p ons i v e), and to M i cros oft for an ev alu ati on v ers i on of V i s u al C + + (J onath an C av es , H erb Su tter, and J as on Sh i rk were ou r contacts th ere).

M u ch of th e ex i s ti ng " C + + wi s dom " was collecti v ely created by th e onli ne C + + com m u ni ty. M os t of i t com es from th e m oderated U s enet g rou p s comp.lang.c++.moderated and comp.std.c++. W e are th erefore es p eci ally i ndebted to th e acti v e m oderators of th os e g rou p s , wh o k eep th e di s cu s s i ons u s efu l and cons tru cti v e. W e als o m u ch ap p reci ate all th os e wh o ov er th e years h av e tak en th e ti m e to des cri be and ex p lai n th ei r i deas for u s all to s h are.

T h e A ddi s on-W es ley team di d anoth er g reat j ob. W e are m os t i ndebted to D ebbi e L afferty (ou r edi tor) for h er g entle p roddi ng , g ood adv i ce, and relentles s h ard work i n s u p p ort of th i s book . T h ank s als o g o to T yrrell A lbau g h , B u nny A m es , M elani e B u ck , J acq u elyn D ou cette, C h anda L eary-C ou tu , C ath eri ne O h ala, and M arty R abi nowi tz . W e' re g ratefu l as well to M ari na L ang , wh o fi rs t s p ons ored th i s book wi th i n A ddi s on-W es ley. Su s an W i ner contri bu ted an early rou nd of edi ti ng th at h elp ed s h ap e ou r later work .

Page 14: CPlusPlus Templates The Complete Guide

Nico's Acknowledgments

M y fi rs t p ers onal th ank s g o wi th a lot of k i s s es to m y fam i ly: U lli , L u cas , A ni ca, and F rederi c s u p p orted th i s book wi th a lot of p ati ence, cons i derati on, and encou rag em ent.

I n addi ti on, I want to th ank D av i d. H i s ex p erti s e tu rned ou t to be i ncredi ble, bu t h i s p ati ence was ev en better (s om eti m es I as k really s i lly q u es ti ons ). I t i s a lot of fu n to work wi th h i m .

Page 15: CPlusPlus Templates The Complete Guide

David's Acknowledgments

M y wi fe, K ari na, h as been i ns tru m ental i n th i s book com i ng to a conclu s i on, and I am i m m ens ely g ratefu l for th e role th at s h e p lays i n m y li fe. W ri ti ng " i n you r s p are ti m e" q u i ck ly becom es errati c wh en m any oth er acti v i ti es v i e for you r s ch edu le. K ari na h elp ed m e to m anag e th at s ch edu le, tau g h t m e to s ay " no" i n order to m ak e th e ti m e needed to m ak e reg u lar p rog res s i n th e wri ti ng p roces s , and abov e all was am az i ng ly s u p p orti v e of th i s p roj ect. I th ank G od ev ery day for h er fri ends h i p and lov e.

I ' m als o trem endou s ly g ratefu l to h av e been able to work wi th N i co. B es i des h i s di rectly v i s i ble contri bu ti ons to th e tex t, h i s ex p eri ence and di s ci p li ne m ov ed u s from m y p i ti fu l doodli ng to a well-org ani z ed p rodu cti on.

J oh n " M r. T em p late" Sp i cer and Stev e " M r. O v erload" A dam cz yk are wonderfu l fri ends and colleag u es , bu t i n m y op i ni on th ey are (tog eth er) als o th e u lti m ate au th ori ty reg ardi ng th e core C + + lang u ag e. T h ey clari fi ed m any of th e tri ck i er i s s u es des cri bed i n th i s book , and s h ou ld you fi nd an error i n th e des cri p ti on of a C + + lang u ag e elem ent, i t i s alm os t certai nly attri bu table to m y fai li ng to cons u lt wi th th em .

F i nally, I want to ex p res s m y ap p reci ati on to th os e wh o were s u p p orti v e of th i s p roj ect wi th ou t neces s ari ly contri bu ti ng to i t di rectly (th e p ower of ch eer cannot be u nders tated). F i rs t, m y p arents : T h ei r lov e for m e and th ei r encou rag em ent m ade all th e di fference. A nd th en th ere are th e nu m erou s fri ends i nq u i ri ng : " H ow i s th e book g oi ng ? " T h ey, too, were a s ou rce of encou rag em ent: M i ch ael B eck m ann, B rett and J u li e B eene, J arran C arr, Si m on C h ang , H o and Sarah C h o, C h ri s top h e D e D i nech i n, E wa D eelm an, N ei l E berle, Sas s an H az eg h i , V i k ram K u m ar, J i m and L i nds ay L ong , R .J . M org an, M i k e P u ri tano, R ag u R ag h av endra, J i m and P h u ong Sh arp , G reg g V au g h n, and J oh n W i eg ley.

Page 16: CPlusPlus Templates The Complete Guide

Chapter 1. About This Book

A lth ou g h tem p lates h av e been p art of C + + for well ov er a decade (and av ai lable i n v ari ou s form s for alm os t as long ), th ey s ti ll lead to m i s u nders tandi ng , m i s u s e, or controv ers y. A t th e s am e ti m e, th ey are i ncreas i ng ly fou nd to be p owerfu l i ns tru m ents for th e dev elop m ent of cleaner, fas ter, and s m arter s oftware. I ndeed, tem p lates h av e becom e th e corners tone of s ev eral new C + + p rog ram m i ng p aradi g m s .

Y et we h av e fou nd th at m os t ex i s ti ng book s and arti cles are at bes t s u p erfi ci al i n th ei r treatm ent of th e th eory and ap p li cati on of C + + tem p lates . E v en th os e few book s th at do an ex cellent j ob of s u rv eyi ng v ari ou s tem p late-bas ed tech ni q u es fai l to des cri be accu rately h ow th es e tech ni q u es are s u p p orted by th e lang u ag e. A s a res u lt, beg i nni ng and adv anced C + + p rog ram m ers ali k e are fi ndi ng th em s elv es wres tli ng wi th tem p lates , attem p ti ng to deci de wh y th ei r code i s h andled u nex p ectedly.

T h i s obs erv ati on was one of th e m ai n m oti v ati ons for u s to wri te th i s book . H owev er, we both cam e u p wi th th e top i c i ndep endently and h ad s om ewh at di s ti nct ap p roach es i n m i nd:

• D av i d' s g oal was to p rov i de a com p lete reference to th e detai ls of th e C + + tem p late lang u ag e m ech ani s m and th e m aj or adv anced p rog ram m i ng tech ni q u es th at tem p lates enable. H i s focu s was on p reci s i on and com p letenes s .

• N i co' s i nteres t was to h av e a book th at h elp s h i m s elf and oth ers u s e tem p lates i n th e day-to-day li fe of a p rog ram m er. T h i s i m p li es th at th e book s h ou ld p res ent th e m ateri al i n an i ntu i ti v e m anner, wh i le deali ng wi th th e p racti cal as p ects of tem p lates .

I n a s ens e, you cou ld s ee u s as a s ci enti s t-eng i neer p ai r: W e both deal wi th th e s am e di s ci p li ne, bu t ou r em p h as i s i s s om ewh at di fferent (wi th m u ch ov erlap , of cou rs e).

A ddi s on-W es ley brou g h t u s tog eth er and as a res u lt you g et wh at we th i nk i s a s oli d com bi nati on of a carefu l C + + tem p late tu tori al wi th a detai led reference. T h e tu tori al as p ect cov ers not only an i ntrodu cti on to th e lang u ag e elem ents , bu t als o ai m s at dev elop i ng a s ens e for des i g n m eth ods th at lead to p racti cal s olu ti ons . Si m i larly, th e book i s not only a reference for th e detai ls of C + + tem p late s yntax and s em anti cs , bu t als o a com p endi u m of well-k nown and les s er k nown i di om s and tech ni q u es .

Page 17: CPlusPlus Templates The Complete Guide
Page 18: CPlusPlus Templates The Complete Guide

1.1 What You Should Know Before Reading This Book

T o g et th e m os t from th i s book you s h ou ld already k now C + + : W e des cri be th e detai ls of a p arti cu lar lang u ag e featu re, not th e fu ndam entals of th e lang u ag e i ts elf. Y ou s h ou ld be fam i li ar wi th th e concep ts of clas s es and i nh eri tance, and you s h ou ld be able to wri te C + + p rog ram s u s i ng com p onents s u ch as I O s tream s and contai ners from th e C + + s tandard li brary. I n addi ti on, we rev i ew m ore s u btle i s s u es as th e need ari s es , ev en wh en s u ch i s s u es aren' t di rectly related to tem p lates . T h i s ens u res th at th e tex t i s acces s i ble to ex p erts and i nterm edi ate p rog ram m ers ali k e.

W e deal m os tly wi th th e C + + lang u ag e as s tandardi z ed i n 19 9 8 (s ee [Standard9 8 ] ), p lu s th e clari fi cati ons p rov i ded by th e C + + Standardi z ati on C om m i ttee i n i ts fi rs t tec hn i c al c or r i g en d u m (s ee [Standard02] ). I f you feel you r u nders tandi ng of th e bas i cs of C + + i s ru s ty or ou t-of-date, we recom m end [Strou s tru p C + + P L ] , [J os u tti s O O P ] , and [J os u tti s StdL i b] to refres h you r k nowledg e. T h es e book s are ex cellent i ntrodu cti ons to th e m odern lang u ag e and i ts s tandard li brary. A ddi ti onal p u bli cati ons are li s ted i n A p p endi x B .3 .5 .

Page 19: CPlusPlus Templates The Complete Guide

1.2 Overall Structure of the Book

O u r g oal i s to p rov i de th e i nform ati on neces s ary for s tarti ng to u s e tem p lates and benefi t from th ei r p ower, as well as to p rov i de i nform ati on th at wi ll enable ex p eri enced p rog ram m ers to p u s h th e li m i ts of th e s tate-of-th e-art. T o ach i ev e th i s , we deci ded to org ani z e ou r tex t i n par ts:

• P art I i ntrodu ces th e bas i c concep ts u nderlyi ng tem p lates . I t i s wri tten i n a tu tori al s tyle.

• P art I I p res ents th e lang u ag e detai ls and i s a h andy reference to tem p late-related cons tru cts .

• P art I I I ex p lai ns fu ndam ental des i g n tech ni q u es s u p p orted by C + + tem p lates . T h ey rang e from near-tri v i al i deas to s op h i s ti cated i di om s th at m ay not h av e been p u bli s h ed els ewh ere.

• P art I V bu i lds on th e p rev i ou s two p arts and adds a di s cu s s i on of v ari ou s p op u lar ap p li cati ons for tem p lates .

E ach of th es e p arts cons i s ts of s ev eral ch ap ters . I n addi ti on, we p rov i de a few ap p endi x es th at cov er m ateri al not ex clu s i v ely related to tem p lates (for ex am p le, an ov erv i ew of ov erload res olu ti on i n C + + ).

T h e ch ap ters of P art I are m eant to be read i n s eq u ence. F or ex am p le, C h ap ter 3 bu i lds on th e m ateri al cov ered i n C h ap ter 2. I n th e oth er p arts , h owev er, th e connecti on between ch ap ters i s cons i derably loos er. F or ex am p le, i t wou ld be enti rely natu ral to read th e ch ap ter abou t f u n c tor s (C h ap ter 22) before th e ch ap ter abou t smar t poi n ter s (C h ap ter 20).

L as t, we p rov i de a rath er com p lete i ndex th at encou rag es addi ti onal ways to read th i s book ou t of s eq u ence.

Page 20: CPlusPlus Templates The Complete Guide

1.3 How to Read This Book

I f you are a C + + p rog ram m er wh o wants to learn or rev i ew th e concep ts of tem p lates , carefu lly read P art I , T h e B as i cs . E v en i f you ' re q u i te fam i li ar wi th tem p lates already, i t m ay h elp to s k i m th rou g h th i s p art q u i ck ly to fam i li ari z e you rs elf wi th th e s tyle and term i nolog y th at we u s e. T h i s p art als o cov ers s om e of th e log i s ti cal as p ects of org ani z i ng you r s ou rce code wh en i t contai ns tem p lates .

D ep endi ng on you r p referred learni ng m eth od, you m ay deci de to abs orb th e m any detai ls of tem p lates i n P art I I , or i ns tead you cou ld read abou t p racti cal codi ng tech ni q u es i n P art I I I (and refer back to P art I I for th e m ore s u btle lang u ag e i s s u es ). T h e latter ap p roach i s p robably p arti cu larly u s efu l i f you bou g h t th i s book wi th concrete day-to-day ch alleng es i n m i nd. P art I V i s s om ewh at s i m i lar to P art I I I , bu t th e em p h as i s i s on u nders tandi ng h ow tem p lates can contri bu te to s p eci fi c ap p li cati ons rath er th an des i g n tech ni q u es . I t i s th erefore p robably bes t to fam i li ari z e you rs elf wi th th e top i cs of P art I I I before delv i ng i nto P art I V .

T h e ap p endi x es contai n m u ch u s efu l i nform ati on th at i s often referred to i n th e m ai n tex t. W e h av e als o tri ed to m ak e th em i nteres ti ng i n th ei r own ri g h t.

I n ou r ex p eri ence, th e bes t way to learn s om eth i ng new i s to look at ex am p les . T h erefore, you ' ll fi nd a lot of ex am p les th rou g h ou t th e book . Som e are j u s t a few li nes of code i llu s trati ng an abs tract concep t, wh ereas oth ers are com p lete p rog ram s th at p rov i de a concrete ap p li cati on of th e m ateri al. T h e latter k i nd of ex am p les wi ll be i ntrodu ced by a C + + com m ent des cri bi ng th e fi le contai ni ng th e p rog ram code. Y ou can fi nd th es e fi les at th e W eb s i te of th i s book at h ttp ://www.j os u tti s .com /tm p lbook /.

Page 21: CPlusPlus Templates The Complete Guide

1.4 Some Remarks About Programming Style

C p rog ram m ers u s e di fferent p rog ram m i ng s tyles , and s o do we: T h e u s u al q u es ti ons abou t wh ere to p u t wh i tes p ace, deli m i ters (braces , p arenth es es ), and s o forth cam e u p . W e tri ed to be cons i s tent i n g eneral, alth ou g h we occas i onally m ak e conces s i ons to th e top i c at h and. F or ex am p le, i n tu tori al s ecti ons we m ay p refer g enerou s u s e of wh i tes p ace and concrete nam es to h elp v i s u ali z e code, wh ereas i n m ore adv anced di s cu s s i ons a m ore com p act s tyle cou ld be m ore ap p rop ri ate.

W e do want to draw you r attenti on to one s li g h tly u ncom m on deci s i on reg ardi ng th e declarati on of typ es , p aram eters , and v ari ables . C learly, s ev eral s tyles are p os s i ble:

void foo (const int &x); void foo (const int& x); void foo (int const &x); void foo (int const& x);

A lth ou g h i t i s a bi t les s com m on, we deci ded to u s e th e order int const rath er th an const int for " cons tant i nteg er." W e h av e two reas ons for th i s . F i rs t, i t p rov i des for an eas i er ans wer to th e q u es ti on, " W hat i s cons tant? " I t' s always wh at i s i n front of th e const q u ali fi er. I ndeed, alth ou g h

const int N = 100;

i s eq u i v alent to

int const N = 100;

th ere i s no eq u i v alent form for

int* const bookmark; // the pointer cannot change, but the // value pointed to can change

th at wou ld p lace th e const q u ali fi er before th e p oi nter op erator *. I n th i s ex am p le, i t i s th e p oi nter i ts elf th at i s cons tant, not th e int to wh i ch i t p oi nts .

O u r s econd reas on h as to do wi th a s yntacti cal s u bs ti tu ti on p ri nci p le th at i s v ery com m on wh en deali ng wi th tem p lates . C ons i der th e followi ng two typ e defi ni ti ons [1]

Page 22: CPlusPlus Templates The Complete Guide

[1]: [1] N ote th at i n C a typ e defi ni ti on defi nes a " typ e ali as " rath er th an a new typ e. F or ex am p le: typedef int Length; // define Length as an alias for int int i = 42; Lengthl = 88; i = l; // OK l = i; // OK

typedef char* CHARS; typedef CHARS const CPTR; // constant pointer to chars

T h e m eani ng of th e s econd declarati on i s p res erv ed wh en we tex tu ally rep lace CHARS wi th wh at i t s tands for:

typedef char* const CPTR; // constant pointer to chars

H owev er, i f we wri te const b ef or e th e typ e i t q u ali fi es , th i s p ri nci p le does n' t ap p ly. I ndeed, cons i der th e alternati v e to ou r fi rs t two typ e defi ni ti ons p res ented earli er:

typedef char* CHARS; typedef const CHARS CPTR; // constant pointer to chars

T ex tu ally rep laci ng CHARS res u lts i n a typ e wi th a di fferent m eani ng :

typedef const char* CPTR; // pointer to constant chars

T h e s am e obs erv ati on ap p li es to th e volatile s p eci fi er, of cou rs e.

R eg ardi ng wh i tes p aces , we deci ded to p u t th e s p ace between th e am p ers and and th e p aram eter nam e:

void foo (int const& x);

B y doi ng th i s , we em p h as i z e th e s ep arati on between th e p aram eter typ e and th e p aram eter nam e. T h i s i s adm i ttedly m ore confu s i ng for declarati ons s u ch as

char* a, b;

wh ere, accordi ng to th e ru les i nh eri ted from C , a i s a p oi nter bu t b i s an ordi nary char. T o av oi d s u ch confu s i on, we s i m p ly av oi d declari ng m u lti p le enti ti es i n th i s

Page 23: CPlusPlus Templates The Complete Guide

way.

T h i s i s not a book abou t th e C s tandard li brary, bu t we do m ak e u s e of th at li brary i n s om e of ou r ex am p les . I n g eneral, we u s e th e C s p eci fi c h eaders (for ex am p le, <iostream> rath er th an <stdio.h>). T h e ex cep ti on i s <stddef.h>. W e u s e i t i ns tead of <cstddef> and th erefore do not q u ali fy size_t and ptrdiff_t wi th th e std:: p refi x becau s e th i s i s s ti ll m ore p ortable and th ere i s no adv antag e i n u s i ng std::size_t i ns tead of size_t.

Page 24: CPlusPlus Templates The Complete Guide

1.5 The Standard versus Reality

T h e C + + s tandard h as been av ai lable s i nce late 19 9 8 . H owev er, i t was not u nti l 2002 th at a p u bli cally av ai lable com p i ler cou ld m ak e th e clai m to " conform fu lly to th e s tandard." T h u s , com p i lers s ti ll di ffer i n th ei r s u p p ort of th e lang u ag e. Sev eral wi ll com p i le m os t of th e code i n th i s book , bu t a few fai rly p op u lar com p i lers m ay not be able to h andle m any of ou r ex am p les . W e often p res ent alternati v e tech ni q u es th at m ay h elp cobble tog eth er a fu ll or p arti al s olu ti on for th es e s u bs tandard C + + i m p lem entati ons , bu t s om e tech ni q u es are cu rrently beyond th ei r reach . Sti ll, we ex p ect th at th i s p roblem wi ll larg ely be res olv ed as p rog ram m ers ev erywh ere dem and s tandard s u p p ort from th ei r v endors .

E v en s o, th e C + + p rog ram m i ng lang u ag e i s li k ely to ev olv e as ti m e p as s es . A lready th e ex p erts of th e C + + com m u ni ty (reg ardles s of wh eth er th ey p arti ci p ate i n th e C + + Standardi z ati on C om m i ttee) are di s cu s s i ng v ari ou s ways to i m p rov e th e lang u ag e, and s ev eral candi date i m p rov em ents affect tem p lates . C h ap ter 13 p res ents s om e trends i n th i s area.

Page 25: CPlusPlus Templates The Complete Guide

1.6 Example Code and Additional Informations

Y ou can acces s all ex am p le p rog ram s and fi nd m ore i nform ati on abou t th i s book from i ts W eb s i te, wh i ch h as th e followi ng U R L :

h ttp ://www.j os u tti s .com /tm p lbook

A ls o, you can fi nd a lot of addi ti onal i nform ati on abou t th i s top i c at D av i d V andev oorde' s W eb s i te at h ttp ://www.v andev oorde.com /T em p lates and on th e W eb i n g eneral. See th e B i bli og rap h y on p ag e 4 9 9 for s u g g es ti ons on wh ere to s tart.

Page 26: CPlusPlus Templates The Complete Guide

1.7 Feedback

W e welcom e you r cons tru cti v e i np u t—both th e neg ati v e and th e p os i ti v e. W e work ed v ery h ard to bri ng you wh at we h op e you ' ll fi nd to be an ex cellent book . H owev er, at s om e p oi nt we h ad to s top wri ti ng , rev i ewi ng , and tweak i ng s o we cou ld " releas e th e p rodu ct." Y ou m ay th erefore fi nd errors , i ncons i s tenci es , and p res entati ons th at cou ld be i m p rov ed, or top i cs th at are m i s s i ng altog eth er. Y ou r feedback g i v es u s a ch ance to i nform all readers th rou g h th e book ' s W eb s i te and to i m p rov e any s u bs eq u ent edi ti ons .

T h e bes t way to reach u s i s by e-m ai l:

tm p lbook @ j os u tti s .com

B e s u re to ch eck th e book ' s W eb s i te for th e cu rrently k nown errata before s u bm i tti ng rep orts .

M any th ank s .

Page 27: CPlusPlus Templates The Complete Guide

Part I: The Basics

T h i s p art i ntrodu ces th e g eneral concep t and lang u ag e featu res of C + + tem p lates . I t s tarts wi th a di s cu s s i on of th e g eneral g oals and concep ts by s h owi ng ex am p les of fu ncti on tem p lates and clas s tem p lates . I t conti nu es wi th s om e addi ti onal fu ndam ental tem p late tech ni q u es s u ch as nontyp e tem p late p aram eters , th e k eyword typename, and m em ber tem p lates . I t ends wi th s om e g eneral h i nts reg ardi ng th e u s e and ap p li cati on of tem p lates i n p racti ce.

T h i s i ntrodu cti on to tem p lates i s als o p arti ally u s ed i n N i colai M . J os u tti s ' s book O b j ec t-O r i en ted Pr og r ammi n g i n C++ , p u bli s h ed by J oh n W i ley and Sons L td, I SB N 0-4 7 0-8 4 3 9 9 -3 . T h i s book teach es all lang u ag e featu res of C + + and th e C + + s tandard li brary and ex p lai ns th ei r p racti cal u s ag e i n a s tep -by-s tep tu tori al.

Why Templates?

C + + req u i res u s to declare v ari ables , fu ncti ons , and m os t oth er k i nds of enti ti es u s i ng s p eci fi c typ es . H owev er, a lot of code look s th e s am e for di fferent typ es . E s p eci ally i f you i m p lem ent alg ori th m s , s u ch as q u i c k sor t , or i f you i m p lem ent th e beh av i or of data s tru ctu res , s u ch as a li nk ed li s t or a bi nary tree for di fferent typ es , th e code look s th e s am e des p i te th e typ e u s ed.

I f you r p rog ram m i ng lang u ag e does n' t s u p p ort a s p eci al lang u ag e featu re for th i s , you only h av e bad alternati v es :

1. Y o u c a n i m p l e m e n t t h e s a m e b e h a v i o r a g a i n a n d a g a i n f o r e a c h t y p e t h a t n e e d s t h i s b e h a v i o r .

2 . Y o u c a n w r i t e g e n e r a l c o d e f o r a c o m m o n b a s e t y p e s u c h a s Object o r void*. 3 . Y o u c a n u s e s p e c i a l p r e p r o c e s s o r s .

I f you com e from C , J av a, or s i m i lar lang u ag es , you p robably h av e done s om e or all of th i s before. H owev er, each of th es e ap p roach es h as i ts drawback s :

1. If y o u i m p l e m e n t a b e h a v i o r a g a i n a n d a g a i n , y o u r e i n v e n t t h e w h e e l . Y o u m a k e t h e s a m e m i s t a k e s a n d y o u t e n d t o a v o i d c o m p l i c a t e d b u t b e t t e r a l g o r i t h m s b e c a u s e t h e y l e a d t o e v e n m o r e m i s t a k e s .

2 . If y o u w r i t e g e n e r a l c o d e f o r a c o m m o n b a s e c l a s s y o u l o s e t h e b e n e f i t o f t y p e c h e c k i n g . In a d d i t i o n , c l a s s e s m a y b e r e q u i r e d t o b e d e r i v e d f r o m s p e c i a l b a s e c l a s s e s , w h i c h m a k e s i t m o r e d i f f i c u l t t o m a i n t a i n y o u r c o d e .

3 . If y o u u s e a s p e c i a l p r e p r o c e s s o r s u c h a s t h e C / C + + p r e p r o c e s s o r , y o u l o s e t h e a d v a n t a g e o f f o r m a t t e d s o u r c e c o d e . C o d e i s r e p l a c e d b y s o m e " s t u p i d t e x t

Page 28: CPlusPlus Templates The Complete Guide

r e p l a c e m e n t m e c h a n i s m " t h a t h a s n o i d e a o f s c o p e a n d t y p e s .

T em p lates are a s olu ti on to th i s p roblem wi th ou t th es e drawback s . T h ey are fu ncti ons or clas s es th at are wri tten for one or m ore typ es not yet s p eci fi ed. W h en you u s e a tem p late, you p as s th e typ es as arg u m ents , ex p li ci tly or i m p li ci tly. B ecau s e tem p lates are lang u ag e featu res , you h av e fu ll s u p p ort of typ e ch eck i ng and s cop e.

I n today' s p rog ram s , tem p lates are u s ed a lot. F or ex am p le, i ns i de th e C + + s tandard li brary alm os t all code i s tem p late code. T h e li brary p rov i des s ort alg ori th m s to s ort obj ects and v alu es of a s p eci fi ed typ e, data s tru ctu res (s o-called c on tai n er c lasses) to m anag e elem ents of a s p eci fi ed typ e, s tri ng s for wh i ch th e typ e of a ch aracter i s p aram eteri z ed, and s o on. H owev er, th i s i s only th e beg i nni ng . T em p lates als o allow u s to p aram eteri z e beh av i or, to op ti m i z e code, and to p aram eteri z e i nform ati on. T h i s i s cov ered i n later ch ap ters . L et' s fi rs t s tart wi th s om e s i m p le tem p lates .

Page 29: CPlusPlus Templates The Complete Guide

Chapter 2. Function Templates

T h i s ch ap ter i ntrodu ces fu ncti on tem p lates . F u ncti on tem p lates are fu ncti ons th at are p aram eteri z ed s o th at th ey rep res ent a fam i ly of fu ncti ons .

Page 30: CPlusPlus Templates The Complete Guide

2.1 A First Look at Function Templates

F u ncti on tem p lates p rov i de a fu ncti onal beh av i or th at can be called for di fferent typ es . I n oth er words , a fu ncti on tem p late rep res ents a fam i ly of fu ncti ons . T h e rep res entati on look s a lot li k e an ordi nary fu ncti on, ex cep t th at s om e elem ents of th e fu ncti on are left u ndeterm i ned: T h es e elem ents are p aram eteri z ed. T o i llu s trate, let' s look at a s i m p le ex am p le.

2.1.1 Defining the Template

T h e followi ng i s a fu ncti on tem p late th at retu rns th e m ax i m u m of two v alu es :

// basics/max.hpp template <typename T> inline T const& max (T const& a, T const& b) { // if a < b then use b else use a return a<b?b:a; }

T h i s tem p late defi ni ti on s p eci fi es a fam i ly of fu ncti ons th at retu rns th e m ax i m u m of two v alu es , wh i ch are p as s ed as fu ncti on p aram eters a and b. T h e typ e of th es e p aram eters i s left op en as template par ameter T. A s s een i n th i s ex am p le, tem p late p aram eters m u s t be annou nced wi th s yntax of th e followi ng form :

template < comma-separated-list-of-parameters >

I n ou r ex am p le, th e li s t of p aram eters i s typename T. N ote h ow th e les s -th an and th e g reater-th an s ym bols are u s ed as brack ets ; we refer to th es e as an g le b r ac k ets. T h e k eyword typename i ntrodu ces a s o-called ty pe par ameter . T h i s i s by far th e m os t com m on k i nd of tem p late p aram eter i n C + + p rog ram s , bu t oth er p aram eters are p os s i ble, and we di s cu s s th em later (s ee C h ap ter 4 ).

H ere, th e typ e p aram eter i s T. Y ou can u s e any i denti fi er as a p aram eter nam e, bu t u s i ng T i s th e conv enti on. T h e typ e p aram eter rep res ents an arbi trary typ e th at i s s p eci fi ed by th e caller wh en th e caller calls th e fu ncti on. Y ou can u s e any typ e (fu ndam ental typ e, clas s , and s o on) as long as i t p rov i des th e op erati ons th at th e tem p late u s es . I n th i s cas e, typ e T h as to s u p p ort op erator < becau s e a and b are com p ared u s i ng th i s op erator.

F or h i s tori cal reas ons , you can als o u s e class i ns tead of typename to defi ne a typ e p aram eter. T h e k eyword typename cam e relati v ely late i n th e ev olu ti on of

Page 31: CPlusPlus Templates The Complete Guide

th e C + + lang u ag e. P ri or to th at, th e k eyword class was th e only way to i ntrodu ce a typ e p aram eter, and th i s rem ai ns a v ali d way to do s o. H ence, th e tem p late max() cou ld be defi ned eq u i v alently as follows :

template <class T> inline T const& max (T const& a, T const& b) { // if a < b then use b else use a return a<b?b:a; }

Sem anti cally th ere i s no di fference i n th i s contex t. So, ev en i f you u s e class h ere, an y typ e m ay be u s ed for tem p late arg u m ents . H owev er, becau s e th i s u s e of class can be m i s leadi ng (not only clas s typ es can be s u bs ti tu ted for T), you s h ou ld p refer th e u s e of typename i n th i s contex t. N ote als o th at u nli k e clas s typ e declarati ons , th e k eyword struct cannot be u s ed i n p lace of typename wh en declari ng typ e p aram eters .

2.1.2 Using the Template

T h e followi ng p rog ram s h ows h ow to u s e th e max() fu ncti on tem p late:

// basics/max.cpp #include <iostream> #include <string> #include "max.hpp" int main() { int i = 42; std::cout << "max(7,i): " << ::max(7,i) << std::endl; double f1 = 3.4; double f2 = -6.7; std::cout << "max(f1,f2): " << ::max(f1,f2) << std::endl; std::string s1 = "mathematics"; std::string s2 = "math"; std::cout << "max(s1,s2): " << ::max(s1,s2) << std::endl; }

I ns i de th e p rog ram , max() i s called th ree ti m es : once for two ints , once for two double s , and once for two std::string s . E ach ti m e, th e m ax i m u m i s com p u ted. A s a res u lt, th e p rog ram h as th e followi ng ou tp u t:

max(7,i): 42 max(f1,f2): 3.4 max(s1,s2): mathematics

Page 32: CPlusPlus Templates The Complete Guide

N ote th at each call of th e max() tem p late i s q u ali fi ed wi th ::. T h i s i s to m ak e s u re th at ou r max() tem p late i s fou nd i n th e g lobal nam es p ace. T h ere i s als o an std::max() tem p late i n th e s tandard li brary, wh i ch u nder s om e ci rcu m s tances m ay be called or m ay lead to am bi g u i ty. [1]

[1] F or ex am p le, i f one arg u m ent typ e i s defi ned i n nam es p ace std (s u ch as s tri ng s ), accordi ng to th e look u p ru les of C + + , both th e g lobal and th e std max() tem p late are fou nd.

N orm ally, tem p lates aren' t com p i led i nto s i ng le enti ti es th at can h andle any typ e. I ns tead, di fferent enti ti es are g enerated from th e tem p late for ev ery typ e for wh i ch th e tem p late i s u s ed. [2 ] T h u s , max() i s com p i led for each of th es e th ree typ es . F or ex am p le, th e fi rs t call of max()

[2 ] T h e " one-enti ty-fi ts -all" alternati v e i s concei v able bu t rare i n p racti ce. A ll lang u ag e ru les are bas ed on th e concep t th at di fferent enti ti es are g enerated.

int i = 42; … max(7,i) …

u s es th e fu ncti on tem p late wi th int as tem p late p aram eter T. T h u s , i t h as th e s em anti cs of calli ng th e followi ng code:

inline int const& max (int const& a, int const& b) { // if a < b then use b else use a return a<b?b:a; }

T h e p roces s of rep laci ng tem p late p aram eters by concrete typ es i s called i n stan ti ati on . I t res u lts i n an i n stan c e of a tem p late. U nfortu nately, th e term s i n stan c e and i n stan ti ate are u s ed i n a di fferent contex t i n obj ect-ori ented p rog ram m i ng —nam ely, for a concrete obj ect of a clas s . H owev er, becau s e th i s book i s abou t tem p lates , we u s e th i s term for th e " u s e" of tem p lates u nles s oth erwi s e s p eci fi ed.

N ote th at th e m ere u s e of a fu ncti on tem p late can tri g g er s u ch an i ns tanti ati on p roces s . T h ere i s no need for th e p rog ram m er to req u es t th e i ns tanti ati on s ep arately.

Si m i larly, th e oth er calls of max() i ns tanti ate th e max tem p late for double and std::string as i f th ey were declared and i m p lem ented i ndi v i du ally:

const double& max (double const&, double const&);

Page 33: CPlusPlus Templates The Complete Guide

const std::string& max (std::string const&, std::string const&);

A n attem p t to i ns tanti ate a tem p late for a typ e th at does n' t s u p p ort all th e op erati ons u s ed wi th i n i t wi ll res u lt i n a com p i le-ti m e error. F or ex am p le:

std::complex<float> c1, c2; // doesn't provide operator < … max(c1,c2); // ERROR at compile time

T h u s , tem p lates are com p i led twi ce:

1. W i t h o u t i n s t a n t i a t i o n , t h e t e m p l a t e c o d e i t s e l f i s c h e c k e d f o r c o r r e c t s y n t a x . S y n t a x e r r o r s a r e d i s c o v e r e d , s u c h a s m i s s i n g s e m i c o l o n s .

2 . A t t h e t i m e o f i n s t a n t i a t i o n , t h e t e m p l a t e c o d e i s c h e c k e d t o e n s u r e t h a t a l l c a l l s a r e v a l i d . In v a l i d c a l l s a r e d i s c o v e r e d , s u c h a s u n s u p p o r t e d f u n c t i o n c a l l s .

T h i s leads to an i m p ortant p roblem i n th e h andli ng of tem p lates i n p racti ce: W h en a fu ncti on tem p late i s u s ed i n a way th at tri g g ers i ts i ns tanti ati on, a com p i ler wi ll (at s om e p oi nt) need to s ee th at tem p late' s defi ni ti on. T h i s break s th e u s u al com p i le and li nk di s ti ncti on for ordi nary fu ncti ons , wh en th e declarati on of a fu ncti on i s s u ffi ci ent to com p i le i ts u s e. M eth ods of h andli ng th i s p roblem are di s cu s s ed i n C h ap ter 6. F or th e m om ent, let' s tak e th e s i m p les t ap p roach : E ach tem p late i s i m p lem ented i ns i de a h eader fi le by u s i ng i nli ne fu ncti ons .

Page 34: CPlusPlus Templates The Complete Guide

2.2 Argument Deduction

W h en we call a fu ncti on tem p late s u ch as max() for s om e arg u m ents , th e tem p late p aram eters are determ i ned by th e arg u m ents we p as s . I f we p as s two ints to th e p aram eter typ es T const& , th e C + + com p i ler m u s t conclu de th at T m u s t be int. N ote th at no au tom ati c typ e conv ers i on i s allowed h ere. E ach T m u s t m atch ex actly. F or ex am p le:

template <typename T> inline T const& max (T const& a, T const& b); … max(4,7) // OK: T is int for both arguments max(4,4.2) // ERROR: first T is int, second T is double

T h ere are th ree ways to h andle s u ch an error:

1. C a s t t h e a r g u m e n t s s o t h a t t h e y b o t h m a t c h : 2.

max(static_cast<double>(4),4.2) // OK

3 . S p e c i f y ( o r q u a l i f y ) e x p l i c i t l y t h e t y p e o f T : 4.

max<double>(4,4.2) // OK

5 . S p e c i f y t h a t t h e p a r a m e t e r s m a y h a v e d i f f e r e n t t y p e s .

F or a detai led di s cu s s i on of th es e top i cs , s ee th e nex t s ecti on.

Page 35: CPlusPlus Templates The Complete Guide

2.3 Template Parameters

F u ncti on tem p lates h av e two k i nds of p aram eters :

1. Template parameters , w h i c h a r e d e c l a r e d i n a n g l e b r a c k e t s b e f o r e t h e f u n c t i o n t e m p l a t e n a m e : 2.

template <typename T> // T is template parameter

3 . C all parameters , w h i c h a r e d e c l a r e d i n p a r e n t h e s e s a f t e r t h e f u n c t i o n t e m p l a t e n a m e : 4.

… max (T const& a, T const& b) // a and b are call parameters

Y ou m ay h av e as m any tem p late p aram eters as you li k e. H owev er, i n fu ncti on tem p lates (u nli k e clas s tem p lates ) no defau lt tem p late arg u m ents can be s p eci fi ed. [3 ] F or ex am p le, you cou ld defi ne th e max() tem p late for call p aram eters of two di fferent typ es :

[3 ] T h i s res tri cti on i s m ai nly th e res u lt of a h i s tori cal g li tch i n th e dev elop m ent of fu ncti on tem p lates . T h ere are p robably no tech ni cal h i ndrances to i m p lem enti ng s u ch a featu re i n m odern C + + com p i lers , and i n th e fu tu re i t wi ll p robably be av ai lable (s ee Secti on 13 .3 on p ag e 207 ).

template <typename T1, typename T2> inline T1 max (T1 const& a, T2 const& b) { return a < b ? b : a; } … max(4,4.2) // OK, but type of first argument defines return type

T h i s m ay ap p ear to be a g ood m eth od to enable p as s i ng two call p aram eters of di fferent typ es to th e max() tem p late, bu t i n th i s ex am p le i t h as drawback s . T h e p roblem i s th at th e retu rn typ e m u s t be declared. I f you u s e one of th e p aram eter typ es , th e arg u m ent for th e oth er p aram eter m i g h t g et conv erted to th i s typ e, reg ardles s of th e caller' s i ntenti on. C + + does not p rov i de a m eans to s p eci fy ch oos i ng " th e m ore p owerfu l typ e" (h owev er, you can p rov i de th i s featu re by s om e tri ck y tem p late p rog ram m i ng , s ee Secti on 15 .2.4 on p ag e 27 1). T h u s , dep endi ng on th e call arg u m ent order th e m ax i m u m of 4 2 and 66.66 m i g h t be th e double 66.66 or th e int 66. A noth er drawback i s th at conv erti ng th e typ e of th e s econd p aram eter i nto th e retu rn typ e creates a new, local tem p orary obj ect. A s a cons eq u ence, you cannot retu rn th e res u lt by reference. [4 ] I n ou r ex am p le, th erefore, th e retu rn typ e h as to be T1 i ns tead of T1 const&.

[4 ] Y ou are not allowed to retu rn v alu es by reference i f th ey are local to a fu ncti on becau s e you ' d retu rn s om eth i ng th at does n' t

Page 36: CPlusPlus Templates The Complete Guide

ex i s t wh en th e p rog ram leav es th e s cop e of th i s fu ncti on.

B ecau s e th e typ es of th e call p aram eters are cons tru cted from th e tem p late p aram eters , tem p late and call p aram eters are u s u ally related. W e call th i s concep t f u n c ti on template ar g u men t d ed u c ti on . I t allows you to call a fu ncti on tem p late as you wou ld an ordi nary fu ncti on.

H owev er, as m enti oned earli er, you can i ns tanti ate a tem p late ex p li ci tly for certai n typ es :

template <typename T> inline T const& max (T const& a, T const& b); … max<double>(4,4.2) // instantiate T as double

I n cas es wh en th ere i s no connecti on between tem p late and call p aram eters and wh en tem p late p aram eters cannot be determ i ned, you m u s t s p eci fy th e tem p late arg u m ent ex p li ci tly wi th th e call. F or ex am p le, you can i ntrodu ce a th i rd tem p late arg u m ent typ e to defi ne th e retu rn typ e of a fu ncti on tem p late:

template <typename T1, typename T2, typename RT> inline RT max (T1 const& a, T2 const& b);

H owev er, tem p late arg u m ent dedu cti on does not m atch u p retu rn typ es , [5 ] and RT does not ap p ear i n th e typ es of th e fu ncti on call p aram eters . T h erefore, RT cannot be dedu ced. A s a cons eq u ence, you h av e to s p eci fy th e tem p late arg u m ent li s t ex p li ci tly. F or ex am p le:

[5 ] D edu cti on can be s een as p art of ov erload res olu ti on—a p roces s th at i s not bas ed on s electi on of retu rn typ es ei th er. T h e s ole ex cep ti on i s th e retu rn typ e of conv ers i on op erator m em bers .

template <typename T1, typename T2, typename RT> inline RT max (T1 const& a, T2 const& b); … max<int,double,double>(4,4.2) // OK, but tedious

So far, we h av e look ed at cas es i n wh i ch ei th er all or none of th e fu ncti on tem p late arg u m ents were m enti oned ex p li ci tly. A noth er ap p roach i s to s p eci fy only th e fi rs t arg u m ents ex p li ci tly and to allow th e dedu cti on p roces s to deri v e th e res t. I n g eneral, you m u s t s p eci fy all th e arg u m ent typ es u p to th e las t arg u m ent typ e th at cannot be determ i ned i m p li ci tly. T h u s , i f you ch ang e th e order of th e tem p late p aram eters i n ou r ex am p le, th e caller needs to s p eci fy only th e retu rn typ e:

template <typename RT, typename T1, typename T2>

Page 37: CPlusPlus Templates The Complete Guide

inline RT max (T1 const& a, T2 const& b); … max<double>(4,4.2) // OK: return type is double

I n th i s ex am p le, th e call to max<double> ex p li ci tly s ets RT to double, bu t th e p aram eters T1 and T2 are dedu ced to be int and double from th e arg u m ents .

N ote th at all of th es e m odi fi ed v ers i ons of max() don' t lead to s i g ni fi cant adv antag es . F or th e one-p aram eter v ers i on you can already s p eci fy th e p aram eter (and retu rn) typ e i f two arg u m ents of a di fferent typ e are p as s ed. T h u s , i t' s a g ood i dea to k eep i t s i m p le and u s e th e one-p aram eter v ers i on of max() (as we do i n th e followi ng s ecti ons wh en di s cu s s i ng oth er tem p late i s s u es ).

See C h ap ter 11 for detai ls of th e dedu cti on p roces s .

Page 38: CPlusPlus Templates The Complete Guide

2.4 Overloading Function Templates

L i k e ordi nary fu ncti ons , fu ncti on tem p lates can be ov erloaded. T h at i s , you can h av e di fferent fu ncti on defi ni ti ons wi th th e s am e fu ncti on nam e s o th at wh en th at nam e i s u s ed i n a fu ncti on call, a C + + com p i ler m u s t deci de wh i ch one of th e v ari ou s candi dates to call. T h e ru les for th i s deci s i on m ay becom e rath er com p li cated, ev en wi th ou t tem p lates . I n th i s s ecti on we di s cu s s ov erloadi ng wh en tem p lates are i nv olv ed. I f you are not fam i li ar wi th th e bas i c ru les of ov erloadi ng wi th ou t tem p lates , p leas e look at A p p endi x B , wh ere we p rov i de a reas onably detai led s u rv ey of th e ov erload res olu ti on ru les .

T h e followi ng s h ort p rog ram i llu s trates ov erloadi ng a fu ncti on tem p late:

// basics/max2.cpp // maximum of two int values inline int const& max (int const& a, int const& b) { return a<b?b:a; } // maximum of two values of any type template <typename T> inline T const& max (T const& a, T const& b) { return a<b?b:a; } // maximum of three values of any type template <typename T> inline T const& max (T const& a, T const& b, T const& c) { return max (max(a,b), c); } int main() { ::max(7, 42, 68); // calls the template for three arguments ::max(7.0, 42.0); // calls max<double> (by argument deduction) ::max('a', 'b'); // calls max<char> (by argument deduction) ::max(7, 42); // calls the nontemplate for two ints ::max<>(7, 42); // calls max<int> (by argument deduction) ::max<double>(7, 42); // calls max<double> (no argument deduction) ::max('a', 42.7); // calls the nontemplate for two ints }

A s th i s ex am p le s h ows , a nontem p late fu ncti on can coex i s t wi th a fu ncti on tem p late th at h as th e s am e nam e and can be i ns tanti ated wi th th e s am e typ e. A ll

Page 39: CPlusPlus Templates The Complete Guide

oth er factors bei ng eq u al, th e ov erload res olu ti on p roces s norm ally p refers th i s nontem p late ov er one g enerated from th e tem p late. T h e fou rth call falls u nder th i s ru le:

max(7, 42) // both int values match the nontemplate function perfectly

I f th e tem p late can g enerate a fu ncti on wi th a better m atch , h owev er, th en th e tem p late i s s elected. T h i s i s dem ons trated by th e s econd and th i rd call of max():

max(7.0, 42.0) // calls the max<double> (by argument deduction) max('a', 'b'); // calls the max<char> (by argument deduction)

I t i s als o p os s i ble to s p eci fy ex p li ci tly an em p ty tem p late arg u m ent li s t. T h i s s yntax i ndi cates th at only tem p lates m ay res olv e a call, bu t all th e tem p late p aram eters s h ou ld be dedu ced from th e call arg u m ents :

max<>(7, 42) // calls max<int> (by argument deduction)

B ecau s e au tom ati c typ e conv ers i on i s not cons i dered for tem p lates bu t i s cons i dered for ordi nary fu ncti ons , th e las t call u s es th e nontem p late fu ncti on (wh i le 'a' and 42.7 both are conv erted to int):

max('a', 42.7) // only the nontemplate function allows different argument types

A m ore u s efu l ex am p le wou ld be to ov erload th e m ax i m u m tem p late for p oi nters and ordi nary C -s tri ng s :

// basics/max3.cpp #include <iostream> #include <cstring> #include <string> // maximum of two values of any type template <typename T> inline T const& max (T const& a, T const& b) { return a < b ? b : a; } // maximum of two pointers template <typename T> inline T* const& max (T* const& a, T* const& b) { return *a < *b ? b : a; }

Page 40: CPlusPlus Templates The Complete Guide

// maximum of two C-strings inline char const* const& max (char const* const& a, char const* const& b) { return std::strcmp(a,b) < 0 ? b : a; } int main () { int a=7; int b=42; ::max(a,b); // max() for two values of type int std::string s="hey"; std::string t="you"; ::max(s,t); // max() for two values of type std::string int* p1 = &b; int* p2 = &a; ::max(p1,p2); // max() for two pointers char const* s1 = "David"; char const* s2 = "Nico"; ::max(s1,s2); // max() for two C-strings }

N ote th at i n all ov erloaded i m p lem entati ons , we p as s all arg u m ents by reference. I n g eneral, i t i s a g ood i dea not to ch ang e m ore th an neces s ary wh en ov erloadi ng fu ncti on tem p lates . Y ou s h ou ld li m i t you r ch ang es to th e nu m ber of p aram eters or to s p eci fyi ng tem p late p aram eters ex p li ci tly. O th erwi s e, u nex p ected effects m ay h ap p en. F or ex am p le, i f you ov erload th e max() tem p late, wh i ch p as s es th e arg u m ents by reference, for two C -s tri ng s p as s ed by v alu e, you can' t u s e th e th ree-arg u m ent v ers i on to com p u te th e m ax i m u m of th ree C -s tri ng s :

// basics/max3a.cpp #include <iostream> #include <cstring> #include <string> // maximum of two values of any type (call-by-reference) template <typename T> inline T const& max (T const& a, T const& b) { return a < b ? b : a; } // maximum of two C-strings (call-by-value) inline char const* max (char const* a, char const* b) { return std::strcmp(a,b) < 0 ? b : a; } // maximum of three values of any type (call-by-reference) template <typename T> inline T const& max (T const& a, T const& b, T const& c)

Page 41: CPlusPlus Templates The Complete Guide

{ return max (max(a,b), c); // error, if max(a,b) uses call-by-value } int main () { ::max(7, 42, 68); // OK const char* s1 = "frederic"; const char* s2 = "anica"; const char* s3 = "lucas"; ::max(s1, s2, s3); // ERROR }

T h e p roblem i s th at i f you call max() for th ree C -s tri ng s , th e s tatem ent

return max (max(a,b), c);

becom es an error. T h i s i s becau s e for C -s tri ng s , max(a,b) creates a new, tem p orary local v alu e th at m ay be retu rned by th e fu ncti on by reference.

T h i s i s only one ex am p le of code th at m i g h t beh av e di fferently th an ex p ected as a res u lt of detai led ov erload res olu ti on ru les . F or ex am p le, th e fact th at not all ov erloaded fu ncti ons are v i s i ble wh en a corres p ondi ng fu ncti on call i s m ade m ay or m ay not m atter. I n fact, defi ni ng a th ree-arg u m ent v ers i on of max() wi th ou t h av i ng s een th e declarati on of a s p eci al two-arg u m ent v ers i on of max() for int s cau s es th e two-arg u m ent tem p late to be u s ed by th e th ree-arg u m ent v ers i on:

// basics/max4.cpp // maximum of two values of any type template <typename T> inline T const& max (T const& a, T const& b) { return a<b?b:a; } // maximum of three values of any type template <typename T> inline T const& max (T const& a, T const& b, T const& c) { return max (max(a,b), c); // uses the template version even for ints } // because the following declaration comes // too late: // maximum of two int values inline int const& max (int const& a, int const& b) { return a<b?b:a; }

Page 42: CPlusPlus Templates The Complete Guide

W e di s cu s s detai ls i n Secti on 9 .2 on p ag e 121, bu t for th e m om ent, as a ru le of th u m b you s h ou ld always h av e all ov erloaded v ers i ons of a fu ncti on declared before th e fu ncti on i s called.

Page 43: CPlusPlus Templates The Complete Guide

2.5 Summary

• T em p late fu ncti ons defi ne a fam i ly of fu ncti ons for di fferent tem p late arg u m ents .

• W h en you p as s tem p late arg u m ents , fu ncti on tem p lates are i ns tanti ated for th es e arg u m ent typ es .

• Y ou can ex p li ci tly q u ali fy th e tem p late p aram eters . • Y ou can ov erload fu ncti on tem p lates . • W h en you ov erload fu ncti on tem p lates , li m i t you r ch ang es to s p eci fyi ng

tem p late p aram eters ex p li ci tly. • M ak e s u re you s ee all ov erloaded v ers i ons of fu ncti on tem p lates before

you call th em .

Page 44: CPlusPlus Templates The Complete Guide

Chapter 3. Class Templates

Si m i lar to fu ncti ons , clas s es can als o be p aram eteri z ed wi th one or m ore typ es . C ontai ner clas s es , wh i ch are u s ed to m anag e elem ents of a certai n typ e, are a typ i cal ex am p le of th i s featu re. B y u s i ng clas s tem p lates , you can i m p lem ent s u ch contai ner clas s es wh i le th e elem ent typ e i s s ti ll op en. I n th i s ch ap ter we u s e a s tack as an ex am p le of a clas s tem p late.

Page 45: CPlusPlus Templates The Complete Guide

3.1 Implementation of Class Template Stack

A s we di d wi th fu ncti on tem p lates , we declare and defi ne clas s Stack<> i n a h eader fi le as follows (we di s cu s s th e s ep arati on of declarati on and defi ni ti on i n di fferent fi les i n Secti on 7 .3 on p ag e 8 9 ):

// basics/stack1.hpp #include <vector> #include <stdexcept> template <typename T> class Stack { private: std::vector<T> elems; // elements public: void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty(); } }; template <typename T> void Stack<T>::push (T const& elem) { elems.push_back(elem); // append copy of passed elem } template<typename T> void Stack<T>::pop () { if (elems.empty()) { throw std::out_of_range("Stack<>::pop(): empty stack"); } elems.pop_back(); // remove last element } template <typename T> T Stack<T>::top () const { if (elems.empty()) { throw std::out_of_range("Stack<>::top(): empty stack"); } return elems.back(); // return copy of last element }

A s you can s ee, th e clas s tem p late i s i m p lem ented by u s i ng a clas s tem p late of th e C + + s tandard li brary: vector<>. A s a res u lt, we don' t h av e to i m p lem ent m em ory m anag em ent, cop y cons tru ctor, and as s i g nm ent op erator, s o we can

Page 46: CPlusPlus Templates The Complete Guide

concentrate on th e i nterface of th i s clas s tem p late.

3.1.1 Declaration of Class Templates

D eclari ng clas s tem p lates i s s i m i lar to declari ng fu ncti on tem p lates : B efore th e declarati on, a s tatem ent declares an i denti fi er as a typ e p aram eter. A g ai n, T i s u s u ally u s ed as an i denti fi er:

template <typename T> class Stack { … };

H ere ag ai n, th e k eyword class can be u s ed i ns tead of typename:

template <class T> class Stack { … };

I ns i de th e clas s tem p late, T can be u s ed j u s t li k e any oth er typ e to declare m em bers and m em ber fu ncti ons . I n th i s ex am p le, T i s u s ed to declare th e typ e of th e elem ents as v ector of Ts , to declare push() as a m em ber fu ncti on th at g ets a cons tant T reference as an arg u m ent, and to declare top() as a fu ncti on th at retu rns a T:

template <typename T> class Stack { private: std::vector<T> elems; // elements public: Stack(); // constructor void push(T const&); // push element void pop(); // pop element T top() const; // return top element };

T h e typ e of th i s clas s i s Stack<T>, wi th T bei ng a tem p late p aram eter. T h u s , you h av e to u s e Stack<T> wh enev er you u s e th e typ e of th i s clas s i n a declarati on. I f, for ex am p le, you h av e to declare you r own cop y cons tru ctor and as s i g nm ent op erator, i t look s li k e th i s [1]:

[1] A ccordi ng to th e s tandard, th ere are s om e ex cep ti ons to th i s ru le (s ee Secti on 9 .2.3 on p ag e 126). H owev er, to be s u re, you s h ou ld always wri te th e fu ll typ e wh en th e typ e i s req u i red.

template <typename T>

Page 47: CPlusPlus Templates The Complete Guide

class Stack { … Stack (Stack<T> const&); // copy constructor Stack<T>& operator= (Stack<T> const&); // assignment operator … };

H owev er, wh en th e nam e and not th e typ e of th e clas s i s req u i red, only Stack h as to be u s ed. T h i s i s th e cas e wh en you s p eci fy th e nam e of th e clas s , th e cons tru ctors , and th e des tru ctor.

3.1.2 Implementation of Member Functions

T o defi ne a m em ber fu ncti on of a clas s tem p late, you h av e to s p eci fy th at i t i s a fu ncti on tem p late, and you h av e to u s e th e fu ll typ e q u ali fi cati on of th e clas s tem p late. T h u s , th e i m p lem entati on of th e m em ber fu ncti on push() for typ e Stack<T> look s li k e th i s :

template <typename T> void Stack<T>::push (T const& elem) { elems.push_back(elem); // append copy of passed elem }

I n th i s cas e, push_back() of th e elem ent v ector i s called, wh i ch ap p ends th e elem ent at th e end of th e v ector.

N ote th at pop_back() of a v ector rem ov es th e las t elem ent bu t does n' t retu rn i t. T h e reas on for th i s beh av i or i s ex cep ti on s afety. I t i s i m p os s i ble to i m p lem ent a com p letely ex cep ti on-s afe v ers i on of pop() th at retu rns th e rem ov ed elem ent (th i s top i c was fi rs t di s cu s s ed by T om C arg i ll i n [C arg i llE x cep ti onSafety] and i s di s cu s s ed as I tem 10 i n [Su tterE x cep ti onal] ). H owev er, i g nori ng th i s dang er, we cou ld i m p lem ent a pop() th at retu rns th e elem ent j u s t rem ov ed. T o do th i s , we s i m p ly u s e T to declare a local v ari able of th e elem ent typ e:

template<typename T> T Stack<T>::pop () { if (elems.empty()) { throw std::out_of_range("Stack<>::pop(): empty stack"); } T elem = elems.back(); // save copy of last element elems.pop_back(); // remove last element return elem; // return copy of saved element }

B ecau s e th e v ectors back() (wh i ch retu rns th e las t elem ent) and pop_back() (wh i ch rem ov es th e las t elem ent) h av e u ndefi ned beh av i or wh en th ere i s no elem ent i n th e v ector, we h av e to ch eck wh eth er th e s tack i s em p ty. I f i t i s

Page 48: CPlusPlus Templates The Complete Guide

em p ty, we th row an ex cep ti on of typ e std::out_of_range. T h i s i s als o done i n top() , wh i ch retu rns bu t does not rem ov e th e top elem ent:

template<typename T> T Stack<T>::top () const { if (elems.empty()) { throw std::out_of_range("Stack<>::top(): empty stack"); } return elems.back(); // return copy of last element }

O f cou rs e, as for any m em ber fu ncti on, you can als o i m p lem ent m em ber fu ncti ons of clas s tem p lates as an i nli ne fu ncti on i ns i de th e clas s declarati on. F or ex am p le:

template <typename T> class Stack { … void push (T const& elem) { elems.push_back(elem); // append copy of passed elem } … };

Page 49: CPlusPlus Templates The Complete Guide

3.2 Use of Class Template Stack

T o u s e an obj ect of a clas s tem p late, you m u s t s p eci fy th e tem p late arg u m ents ex p li ci tly. T h e followi ng ex am p le s h ows h ow to u s e th e clas s tem p late Stack<>:

// basics/stack1test.cpp #include <iostream> #include <string> #include <cstdlib> #include "stack1.hpp" int main() { try { Stack<int> intStack; // stack of ints Stack<std::string> stringStack; // stack of strings // manipulate int stack intStack.push(7); std::cout << intStack.top() << std::endl; // manipulate string stack stringStack.push("hello"); std::cout << stringStack.top() << std::endl; stringStack.pop(); stringStack.pop(); } catch (std::exception const& ex) { std::cerr << "Exception: " << ex.what() << std::endl; return EXIT_FAILURE; // exit program with ERROR status } }

B y declari ng typ e Stack<int> , int i s u s ed as typ e T i ns i de th e clas s tem p late. T h u s , intStack i s created as an obj ect th at u s es a v ector of ints as elem ents and, for all m em ber fu ncti ons th at are called, code for th i s typ e i s i ns tanti ated. Si m i larly, by declari ng and u s i ng Stack<std::string>, an obj ect th at u s es a v ector of s tri ng s as elem ents i s created, and for all m em ber fu ncti ons th at are called, code for th i s typ e i s i ns tanti ated.

N ote th at code i s i ns tanti ated only for memb er f u n c ti on s that ar e c alled . F or clas s tem p lates , m em ber fu ncti ons are i ns tanti ated only wh en th ey are u s ed. T h i s , of cou rs e, s av es ti m e and s p ace. I t h as th e addi ti onal benefi t th at you can i ns tanti ate a clas s ev en for th os e typ es th at cannot p erform all th e op erati ons of all th e m em ber fu ncti ons , as long as th es e m em ber fu ncti ons are not called. A s an ex am p le, cons i der a clas s i n wh i ch s om e m em ber fu ncti ons u s e th e op erator < to s ort elem ents . I f you refrai n from calli ng th es e m em ber fu ncti ons , you can

Page 50: CPlusPlus Templates The Complete Guide

i ns tanti ate th e clas s tem p late for typ es for wh i ch op erator < i s not defi ned.

I n th i s ex am p le, th e defau lt cons tru ctor, push(), and top() are i ns tanti ated for both int and s tri ng s . H owev er, pop() i s i ns tanti ated only for s tri ng s . I f a clas s tem p late h as s tati c m em bers , th es e are i ns tanti ated once for each typ e.

Y ou can u s e a typ e of an i ns tanti ated clas s tem p late as any oth er typ e, as long as th e op erati ons are s u p p orted:

void foo (Stack<int> const& s) // parameter s is int stack { Stack<int> istack[10]; // istack is array of 10 int stacks … }

B y u s i ng a typ e defi ni ti on, you can m ak e u s i ng a clas s tem p late m ore conv eni ent:

typedef Stack<int> IntStack; void foo (IntStack const& s) // s is stack of ints { IntStack istack[10]; // istack is array of 10 stacks of ints … }

N ote th at i n C + + a typ e defi ni ti on does defi ne a " typ e ali as " rath er th an a new typ e. T h u s , after th e typ e defi ni ti on

typedef Stack<int> IntStack;

IntStack and Stack<int> are th e s am e typ e and can be u s ed for and as s i g ned to each oth er.

T em p late arg u m ents m ay be any typ e, s u ch as p oi nters to float s or ev en s tack s of int s :

Stack<float*> floatPtrStack; // stack of float pointers Stack<Stack<int> > intStackStack; // stack of stack of ints

T h e only req u i rem ent i s th at any op erati on th at i s called i s p os s i ble accordi ng to th i s typ e.

N ote th at you h av e to p u t wh i tes p ace between th e two clos i ng tem p late brack ets .

Page 51: CPlusPlus Templates The Complete Guide

I f you don' t do th i s , you are u s i ng op erator >>, wh i ch res u lts i n a s yntax error:

Stack<Stack<int>> intStackStack; // ERROR: >> is not allowed

Page 52: CPlusPlus Templates The Complete Guide

3.3 Specializations of Class Templates

Y ou can s p eci ali z e a clas s tem p late for certai n tem p late arg u m ents . Si m i lar to th e ov erloadi ng of fu ncti on tem p lates (s ee p ag e 15 ), s p eci ali z i ng clas s tem p lates allows you to op ti m i z e i m p lem entati ons for certai n typ es or to fi x a m i s beh av i or of certai n typ es for an i ns tanti ati on of th e clas s tem p late. H owev er, i f you s p eci ali z e a clas s tem p late, you m u s t als o s p eci ali z e all m em ber fu ncti ons . A lth ou g h i t i s p os s i ble to s p eci ali z e a s i ng le m em ber fu ncti on, once you h av e done s o, you can no long er s p eci ali z e th e wh ole clas s .

T o s p eci ali z e a clas s tem p late, you h av e to declare th e clas s wi th a leadi ng template<> and a s p eci fi cati on of th e typ es for wh i ch th e clas s tem p late i s s p eci ali z ed. T h e typ es are u s ed as a tem p late arg u m ent and m u s t be s p eci fi ed di rectly followi ng th e nam e of th e clas s :

template<> class Stack<std::string> { … };

F or th es e s p eci ali z ati ons , any defi ni ti on of a m em ber fu ncti on m u s t be defi ned as an " ordi nary" m em ber fu ncti on, wi th each occu rrence of T bei ng rep laced by th e s p eci ali z ed typ e:

void Stack<std::string>::push (std::string const& elem) { elems.push_back(elem); // append copy of passed elem }

H ere i s a com p lete ex am p le of a s p eci ali z ati on of Stack<> for typ e std::string:

// basics/stack2.hpp #include <deque> #include <string> #include <stdexcept> #include "stack1.hpp" template<> class Stack<std::string> { private: std::deque<std::string> elems; // elements public: void push(std::string const&); // push element

Page 53: CPlusPlus Templates The Complete Guide

void pop(); // pop element std::string top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty(); } }; void Stack<std::string>::push (std::string const& elem) { elems.push_back(elem); // append copy of passed elem } void Stack<std::string>::pop () { if (elems.empty()) { throw std::out_of_range ("Stack<std::string>::pop(): empty stack"); } elems.pop_back(); // remove last element } std::string Stack<std::string>::top () const { if (elems.empty()) { throw std::out_of_range ("Stack<std::string>::top(): empty stack"); } return elems.back(); // return copy of last element }

I n th i s ex am p le, a deq u e i ns tead of a v ector i s u s ed to m anag e th e elem ents i ns i de th e s tack . A lth ou g h th i s h as no p arti cu lar benefi t h ere, i t does dem ons trate th at th e i m p lem entati on of a s p eci ali z ati on m i g h t look v ery di fferent from th e i m p lem entati on of th e p ri m ary tem p late. [2 ]

[2 ] I n fact, th ere i s a benefi t for u s i ng a deq u e i ns tead of a v ector to i m p lem ent a s tack : A deq u e frees m em ory wh en elem ents are rem ov ed, and i t can' t h ap p en th at elem ents h av e to be m ov ed as a res u lt of reallocati on. H owev er, th i s i s no p arti cu lar benefi t for s tri ng s . F or th i s reas on i t i s p robably a g ood i dea to u s e a deq u e i n th e p ri m ary clas s tem p late (as i s th e cas e i n clas s std::stack<> of th e C + + s tandard li brary).

Page 54: CPlusPlus Templates The Complete Guide

3.4 Partial Specialization

C las s tem p lates can be p arti ally s p eci ali z ed. Y ou can s p eci fy s p eci al i m p lem entati ons for p arti cu lar ci rcu m s tances , bu t s om e tem p late p aram eters m u s t s ti ll be defi ned by th e u s er. F or ex am p le, for th e followi ng clas s tem p late

template <typename T1, typename T2> class MyClass { … };

th e followi ng p arti al s p eci ali z ati ons are p os s i ble:

// partial specialization: both template parameters have same type template <typename T> class MyClass<T,T> { … }; // partial specialization: second type is int template <typename T> class MyClass<T,int> { … }; // partial specialization: both template parameters are pointer types template <typename T1, typename T2> class MyClass<T1*,T2*> { … };

T h e followi ng ex am p le s h ows wh i ch tem p late i s u s ed by wh i ch declarati on:

MyClass<int,float> mif; // uses MyClass<T1,T2> MyClass<float,float> mff; // uses MyClass<T,T> MyClass<float,int> mfi; // uses MyClass<T,int> MyClass<int*,float*> mp; // uses MyClass<T1*,T2*>

I f m ore th an one p arti al s p eci ali z ati on m atch es eq u ally well, th e declarati on i s am bi g u ou s :

MyClass<int,int> m; // ERROR: matches MyClass<T,T> // and MyClass<T,int> MyClass<int*,int*> m; // ERROR: matches MyClass<T,T> // and MyClass<T1*,T2*>

T o res olv e th e s econd am bi g u i ty, you can p rov i de an addi ti onal p arti al

Page 55: CPlusPlus Templates The Complete Guide

s p eci ali z ati on for p oi nters of th e s am e typ e:

template <typename T> class MyClass<T*,T*> { … };

F or detai ls , s ee Secti on 12.4 on p ag e 200.

Page 56: CPlusPlus Templates The Complete Guide

3.5 Default Template Arguments

F or clas s tem p lates you can als o defi ne defau lt v alu es for tem p late p aram eters . T h es e v alu es are called d ef au lt template ar g u men ts. T h ey m ay ev en refer to p rev i ou s tem p late p aram eters . F or ex am p le, i n clas s Stack<> you can defi ne th e contai ner th at i s u s ed to m anag e th e elem ents as a s econd tem p late p aram eter, u s i ng std::vector<> as th e defau lt v alu e:

// basics/stack3.hpp #include <vector> #include <stdexcept> template <typename T, typename CONT = std::vector<T> > class Stack { private: CONT elems; // elements public: void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty(); } }; template <typename T, typename CONT> void Stack<T,CONT>::push (T const& elem) { elems.push_back(elem); // append copy of passed elem } template <typename T, typename CONT> void Stack<T,CONT>::pop () { if (elems.empty()) { throw std::out_of_range("Stack<>::pop(): empty stack"); } elems.pop_back(); // remove last element } template <typename T, typename CONT> T Stack<T,CONT>::top () const { if (elems.empty()) { throw std::out_of_range("Stack<>::top(): empty stack"); } return elems.back(); // return copy of last element }

N ote th at we now h av e two tem p late p aram eters , s o each defi ni ti on of a m em ber

Page 57: CPlusPlus Templates The Complete Guide

fu ncti on m u s t be defi ned wi th th es e two p aram eters :

template <typename T, typename CONT> void Stack<T,CONT>::push (T const& elem) { elems.push_back(elem); // append copy of passed elem }

Y ou can u s e th i s s tack th e s am e way i t was u s ed before. T h u s , i f you p as s a fi rs t and only arg u m ent as an elem ent typ e, a v ector i s u s ed to m anag e th e elem ents of th i s typ e:

template <typename T, typename CONT = std::vector<T> > class Stack { private: CONT elems; // elements … };

I n addi ti on, you cou ld s p eci fy th e contai ner for th e elem ents wh en you declare a Stack obj ect i n you r p rog ram :

// basics/stack3test.cpp #include <iostream> #include <deque> #include <cstdlib> #include "stack3.hpp" int main() { try { // stack of ints: Stack<int> intStack; // stack of doubles which uses a std::deque<> to mange the elements Stack<double,std::deque<double> > dblStack; // manipulate int stack intStack.push(7); std::cout << intStack.top() << std::endl; intStack.pop(); // manipulate double stack dblStack.push(42.42); std::cout << dblStack.top() << std::endl; dblStack.pop(); dblStack.pop(); } catch (std::exception const& ex) { std::cerr << "Exception: " << ex.what() << std::endl; return EXIT_FAILURE; // exit program with ERROR status }

Page 58: CPlusPlus Templates The Complete Guide

}

W i th

Stack<double,std::deque<double> >

you declare a s tack for double s th at u s es a std::deque<> to m anag e th e elem ents i nternally.

Page 59: CPlusPlus Templates The Complete Guide

3.6 Summary

• A clas s tem p late i s a clas s th at i s i m p lem ented wi th one or m ore typ e p aram eters left op en.

• T o u s e a clas s tem p late, you p as s th e op en typ es as tem p late arg u m ents . T h e clas s tem p late i s th en i ns tanti ated (and com p i led) for th es e typ es .

• F or clas s tem p lates , only th os e m em ber fu ncti ons th at are called are i ns tanti ated.

• Y ou can s p eci ali z e clas s tem p lates for certai n typ es . • Y ou can p arti ally s p eci ali z e clas s tem p lates for certai n typ es . • Y ou can defi ne defau lt v alu es for clas s tem p late p aram eters . T h es e m ay

refer to p rev i ou s tem p late p aram eters .

Page 60: CPlusPlus Templates The Complete Guide

Chapter 4. Nontype Template Parameters

F or fu ncti on and clas s tem p lates , tem p late p aram eters don' t h av e to be typ es . T h ey can als o be ordi nary v alu es . A s wi th tem p lates u s i ng typ e p aram eters , you defi ne code for wh i ch a certai n detai l rem ai ns op en u nti l th e code i s u s ed. H owev er, th e detai l th at i s op en i s a v alu e i ns tead of a typ e. W h en u s i ng s u ch a tem p late, you h av e to s p eci fy th i s v alu e ex p li ci tly. T h e res u lti ng code th en g ets i ns tanti ated. T h i s ch ap ter i llu s trates th i s featu re for a new v ers i on of th e s tack clas s tem p late. I n addi ti on, we s h ow an ex am p le of nontyp e fu ncti on tem p late p aram eters and di s cu s s s om e res tri cti ons to th i s tech ni q u e.

Page 61: CPlusPlus Templates The Complete Guide

4.1 Nontype Class Template Parameters

I n contras t to th e s am p le i m p lem entati ons of a s tack i n p rev i ou s ch ap ters , you can als o i m p lem ent a s tack by u s i ng a fi x ed-s i z e array for th e elem ents . A n adv antag e of th i s m eth od i s th at th e m em ory m anag em ent ov erh ead, wh eth er p erform ed by you or by a s tandard contai ner, i s av oi ded. H owev er, determ i ni ng th e bes t s i z e for s u ch a s tack can be ch alleng i ng . T h e s m aller th e s i z e you s p eci fy, th e m ore li k ely i t i s th at th e s tack wi ll g et fu ll. T h e larg er th e s i z e you s p eci fy, th e m ore li k ely i t i s th at m em ory wi ll be res erv ed u nneces s ari ly. A g ood s olu ti on i s to let th e u s er of th e s tack s p eci fy th e s i z e of th e array as th e m ax i m u m s i z e needed for s tack elem ents .

T o do th i s , defi ne th e s i z e as a tem p late p aram eter:

// basics/stack4.hpp #include <stdexcept> template <typename T, int MAXSIZE> class Stack { private: T elems[MAXSIZE]; // elements int numElems; // current number of elements public: Stack(); // constructor void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const { // return whether the stack is empty return numElems == 0; } bool full() const { // return whether the stack is full return numElems == MAXSIZE; } }; // constructor template <typename T, int MAXSIZE> Stack<T,MAXSIZE>::Stack () : numElems(0) // start with no elements { // nothing else to do } template <typename T, int MAXSIZE> void Stack<T,MAXSIZE>::push (T const& elem) { if (numElems == MAXSIZE) { throw std::out_of_range("Stack<>::push(): stack is full"); } elems[numElems] = elem; // append element

Page 62: CPlusPlus Templates The Complete Guide

++numElems; // increment number of elements } template<typename T, int MAXSIZE> void Stack<T,MAXSIZE>::pop () { if (numElems <= 0) { throw std::out_of_range("Stack<>::pop(): empty stack"); } --numElems; // decrement number of elements } template <typename T, int MAXSIZE> T Stack<T,MAXSIZE>::top () const { if (numElems <= 0) { throw std::out_of_range("Stack<>::top(): empty stack"); } return elems[numElems-1]; // return last element }

T h e new s econd tem p late p aram eter, MAXSIZE , i s of typ e int. I t s p eci fi es th e s i z e of th e array of s tack elem ents :

template <typename T, int MAXSIZE> class Stack { private: T elems[MAXSIZE]; // elements … };

I n addi ti on, i t i s u s ed i n push() to ch eck wh eth er th e s tack i s fu ll:

template <typename T, int MAXSIZE> void Stack<T,MAXSIZE>::push (T const& elem) { if (numElems == MAXSIZE) { throw "Stack<>::push(): stack is full"; } elems[numElems] = elem; // append element ++numElems; // increment number of elements }

T o u s e th i s clas s tem p late you h av e to s p eci fy both th e elem ent typ e and th e m ax i m u m s i z e:

// basics/stack4test.cpp #include <iostream> #include <string> #include <cstdlib> #include "stack4.hpp" int main()

Page 63: CPlusPlus Templates The Complete Guide

{ try { Stack<int,20> int20Stack; // stack of up to 20 ints Stack<int,40> int40Stack; // stack of up to 40 ints Stack<std::string,40> stringStack; // stack of up to 40 strings // manipulate stack of up to 20 ints int20Stack.push(7); std::cout << int20Stack.top() << std::endl; int20Stack.pop(); // manipulate stack of up to 40 strings stringStack.push("hello"); std::cout << stringStack.top() << std::endl; stringStack.pop(); stringStack.pop(); } catch (std::exception const& ex) { std::cerr << "Exception: " << ex.what() << std::endl; return EXIT_FAILURE; // exit program with ERROR status } }

N ote th at each tem p late i ns tanti ati on i s i ts own typ e. T h u s , int20Stack and int40Stack are two di fferent typ es , and no i m p li ci t or ex p li ci t typ e conv ers i on between th em i s defi ned. T h u s , one cannot be u s ed i ns tead of th e oth er, and you cannot as s i g n one to th e oth er.

A g ai n, defau lt v alu es for th e tem p late p aram eters can be s p eci fi ed:

template <typename T = int, int MAXSIZE = 100> class Stack { … };

H owev er, from a p ers p ecti v e of g ood des i g n, th i s m ay not be ap p rop ri ate i n th i s ex am p le. D efau lt v alu es s h ou ld be i ntu i ti v ely correct. B u t nei th er typ e int nor a m ax i m u m s i z e of 100 s eem s i ntu i ti v e for a g eneral s tack typ e. T h u s , i t i s better wh en th e p rog ram m er h as to s p eci fy both v alu es ex p li ci tly s o th at th es e two attri bu tes are always docu m ented du ri ng a declarati on.

Page 64: CPlusPlus Templates The Complete Guide

4.2 Nontype Function Template Parameters

Y ou can als o defi ne nontyp e p aram eters for fu ncti on tem p lates . F or ex am p le, th e followi ng fu ncti on tem p late defi nes a g rou p of fu ncti ons for wh i ch a certai n v alu e can be added:

// basics/addval.hpp template <typename T, int VAL> T addValue (T const& x) { return x + VAL; }

T h es e k i nds of fu ncti ons are u s efu l i f fu ncti ons or op erati ons i n g eneral are u s ed as p aram eters . F or ex am p le, i f you u s e th e Standard T em p late L i brary (ST L ) you can p as s an i ns tanti ati on of th i s fu ncti on tem p late to add a v alu e to each elem ent of a collecti on:

std::transform (source.begin(), source.end(), // start and end of source dest.begin(), // start of destination addValue<int,5>); // operation

T h e las t arg u m ent i ns tanti ates th e fu ncti on tem p late addValue() to add 5 to an int v alu e. T h e res u lti ng fu ncti on i s called for each elem ent i n th e s ou rce collecti on source , wh i le i t i s trans lated i nto th e des ti nati on collecti on dest.

N ote th at th ere i s a p roblem wi th th i s ex am p le: addValue<int,5> i s a fu ncti on tem p late, and fu ncti on tem p lates are cons i dered to nam e a s et of ov erloaded fu ncti ons (ev en i f th e s et h as only one m em ber). H owev er, accordi ng to th e cu rrent s tandard, s ets of ov erloaded fu ncti ons cannot be u s ed for tem p late p aram eter dedu cti on. T h u s , you h av e to cas t to th e ex act typ e of th e fu ncti on tem p late arg u m ent:

std::transform (source.begin(), source.end(), // start and end of source dest.begin(), // start of destination (int(*)(int const&)) addValue<int,5>); // operation

T h ere i s a p rop os al for th e s tandard to fi x th i s beh av i or s o th at th e cas t i s n' t neces s ary i n th i s contex t (s ee [C oreI s s u e115 ] for detai ls ), bu t u nti l th en th e cas t

Page 65: CPlusPlus Templates The Complete Guide

m ay be neces s ary to be p ortable.

Page 66: CPlusPlus Templates The Complete Guide

4.3 Restrictions for Nontype Template Parameters

N ote th at nontyp e tem p late p aram eters carry s om e res tri cti ons . I n g eneral, th ey m ay be cons tant i nteg ral v alu es (i nclu di ng enu m erati ons ) or p oi nters to obj ects wi th ex ternal li nk ag e.

F loati ng -p oi nt nu m bers and clas s -typ e obj ects are not allowed as nontyp e tem p late p aram eters :

template <double VAT> // ERROR: floating-point values are not double process (double v) // allowed as template parameters { return v * VAT; } template <std::string name> // ERROR: class-type objects are not class MyClass { // allowed as template parameters … };

N ot bei ng able to u s e floati ng -p oi nt li terals (and s i m p le cons tant floati ng -p oi nt ex p res s i ons ) as tem p late arg u m ents h as h i s tori cal reas ons . B ecau s e th ere are no s eri ou s tech ni cal ch alleng es , th i s m ay be s u p p orted i n fu tu re v ers i ons of C + + (s ee Secti on 13 .4 on p ag e 210).

B ecau s e s tri ng li terals are obj ects wi th i nternal li nk ag e (two s tri ng li terals wi th th e s am e v alu e bu t i n di fferent m odu les are di fferent obj ects ), you can' t u s e th em as tem p late arg u m ents ei th er:

template <char const* name> class MyClass { … }; MyClass<"hello"> x; // ERROR: string literal "hello" not allowed

Y ou cannot u s e a g lobal p oi nter ei th er:

template <char const* name> class MyClass { … }; char const* s = "hello"; MyClass<s> x; // ERROR: s is pointer to object with internal linkage

Page 67: CPlusPlus Templates The Complete Guide

H owev er, th e followi ng i s p os s i ble:

template <char const* name> class MyClass { … }; extern char const s[] = "hello"; MyClass<s> x; // OK

T h e g lobal ch aracter array s i s i ni ti ali z ed by "hello" s o th at s i s an obj ect wi th ex ternal li nk ag e.

See Secti on 8 .3 .3 on p ag e 109 for a detai led di s cu s s i on and Secti on 13 .4 on p ag e 209 for a di s cu s s i on of p os s i ble fu tu re ch ang es i n th i s area.

Page 68: CPlusPlus Templates The Complete Guide

4.4 Summary

• T em p lates can h av e tem p late p aram eters th at are v alu es rath er th an typ es .

• Y ou cannot u s e floati ng -p oi nt nu m bers , clas s -typ e obj ects , and obj ects wi th i nternal li nk ag e (s u ch as s tri ng li terals ) as arg u m ents for nontyp e tem p late p aram eters .

Page 69: CPlusPlus Templates The Complete Guide

Chapter 5. Tricky Basics

T h i s ch ap ter cov ers s om e fu rth er bas i c as p ects of tem p lates th at are relev ant to th e p racti cal u s e of tem p lates : an addi ti onal u s e of th e typename k eyword, defi ni ng m em ber fu ncti ons and nes ted clas s es as tem p lates , tem p late tem p late p aram eters , z ero i ni ti ali z ati on, and s om e detai ls abou t u s i ng s tri ng li terals as arg u m ents for fu ncti on tem p lates . T h es e as p ects can be tri ck y at ti m es , bu t ev ery day-to-day p rog ram m er s h ou ld h av e h eard of th em .

Page 70: CPlusPlus Templates The Complete Guide

5.1 Keyword typename

T h e k eyword typename was i ntrodu ced du ri ng th e s tandardi z ati on of C + + to clari fy th at an i denti fi er i ns i de a tem p late i s a typ e. C ons i der th e followi ng ex am p le:

template <typename T> class MyClass { typename T::SubType * ptr; … };

H ere, th e s econd typename i s u s ed to clari fy th at SubType i s a typ e defi ned wi th i n clas s T. T h u s , ptr i s a p oi nter to th e typ e T::SubType.

W i th ou t typename, SubType wou ld be cons i dered a s tati c m em ber. T h u s , i t wou ld be a concrete v ari able or obj ect. A s a res u lt, th e ex p res s i on

T::SubType * ptr

wou ld be a m u lti p li cati on of th e s tati c SubType m em ber of clas s T wi th ptr.

I n g eneral, typename h as to be u s ed wh enev er a nam e th at dep ends on a tem p late p aram eter i s a typ e. T h i s i s di s cu s s ed i n detai l i n Secti on 9 .3 .2 on p ag e 13 0.

A typ i cal ap p li cati on of typename i s th e acces s to i terators of ST L contai ners i n tem p late code:

// basics/printcoll.hpp #include <iostream> // print elements of an STL container template <typename T> void printcoll (T const& coll) { typename T::const_iterator pos; // iterator to iterate over coll typename T::const_iterator end(coll.end()); // end position for (pos=coll.begin(); pos!=end; ++pos) { std::cout << *pos << ' '; } std::cout << std::endl; }

Page 71: CPlusPlus Templates The Complete Guide

I n th i s fu ncti on tem p late, th e call p aram eter i s an ST L contai ner of typ e T. T o i terate ov er all elem ents of th e contai ner, th e i terator typ e of th e contai ner i s u s ed, wh i ch i s declared as typ e const_iterator i ns i de each ST L contai ner clas s :

class stlcontainer { … typedef … iterator; // iterator for read/write access typedef … const_iterator; // iterator for read access … };

T h u s , to acces s typ e const_iterator of tem p late typ e T, you h av e to q u ali fy i t wi th a leadi ng typename:

typename T::const_iterator pos;

The .template Construct

A v ery s i m i lar p roblem was di s cov ered after th e i ntrodu cti on of typename. C ons i der th e followi ng ex am p le u s i ng th e s tandard bitset typ e:

template<int N> void printBitset (std::bitset<N> const& bs) { std::cout << bs.template to_string<char,char_traits<char>, allocator<char> >(); }

T h e s trang e cons tru ct i n th i s ex am p le i s .template. W i th ou t th at ex tra u s e of template, th e com p i ler does not k now th at th e les s -th an tok en (<) th at follows i s not really " les s th an" bu t th e beg i nni ng of a tem p late arg u m ent li s t. N ote th at th i s i s a p roblem only i f th e cons tru ct before th e p eri od dep ends on a tem p late p aram eter. I n ou r ex am p le, th e p aram eter bs dep ends on th e tem p late p aram eter N.

I n conclu s i on, th e .template notati on (and s i m i lar notati ons s u ch as ->template) s h ou ld be u s ed only i ns i de tem p lates and only i f th ey follow s om eth i ng th at dep ends on a tem p late p aram eter. See Secti on 9 .3 .3 on p ag e 13 2 for detai ls .

Page 72: CPlusPlus Templates The Complete Guide

5.2 Using this->

F or clas s tem p lates wi th bas e clas s es , u s i ng a nam e x by i ts elf i s not always eq u i v alent to this->x, ev en th ou g h a m em ber x i s i nh eri ted. F or ex am p le:

template <typename T> class Base { public: void exit(); }; template <typename T> class Derived : Base<T> { public: void foo() { exit(); // calls external exit() or error } };

I n th i s ex am p le, for res olv i ng th e s ym bol exit i ns i de foo() , exit() defi ned i n Base i s n ev er cons i dered. T h erefore, ei th er you h av e an error, or anoth er exit() (s u ch as th e s tandard exit()) i s called.

W e di s cu s s th i s i s s u e i n Secti on 9 .4 .2 on p ag e 13 6 i n detai l. F or th e m om ent, as a ru le of th u m b, we recom m end th at you always q u ali fy any s ym bol th at i s declared i n a bas e th at i s s om eh ow dep endent on a tem p late p aram eter wi th this-> or Base<T>::. I f you want to av oi d all u ncertai nty, you m ay cons i der q u ali fyi ng all m em ber acces s es (i n tem p lates ).

Page 73: CPlusPlus Templates The Complete Guide

5.3 Member Templates

C las s m em bers can als o be tem p lates . T h i s i s p os s i ble for both nes ted clas s es and m em ber fu ncti ons . T h e ap p li cati on and adv antag e of th i s abi li ty can ag ai n be dem ons trated wi th th e Stack<> clas s tem p late. N orm ally you can as s i g n s tack s to each oth er only wh en th ey h av e th e s am e typ e, wh i ch i m p li es th at th e elem ents h av e th e s am e typ e. H owev er, you can' t as s i g n a s tack wi th elem ents of any oth er typ e, ev en i f th ere i s an i m p li ci t typ e conv ers i on for th e elem ent typ es defi ned:

Stack<int> intStack1, intStack2; // stacks for ints Stack<float> floatStack; // stack for floats … intStack1 = intStack2; // OK: stacks have same type floatStack = intStack1; // ERROR: stacks have different types

T h e defau lt as s i g nm ent op erator req u i res th at both s i des of th e as s i g nm ent op erator h av e th e s am e typ e, wh i ch i s not th e cas e i f s tack s h av e di fferent elem ent typ es .

B y defi ni ng an as s i g nm ent op erator as a tem p late, h owev er, you can enable th e as s i g nm ent of s tack s wi th elem ents for wh i ch an ap p rop ri ate typ e conv ers i on i s defi ned. T o do th i s you h av e to declare Stack<> as follows :

// basics/stack5decl.hpp template <typename T> class Stack { private: std::deque<T> elems; // elements public: void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty(); } // assign stack of elements of type T2 template <typename T2> Stack<T>& operator= (Stack<T2> const&); };

T h e followi ng two ch ang es h av e been m ade:

1. W e a d d e d a d e c l a r a t i o n o f a n a s s i g n m e n t o p e r a t o r f o r s t a c k s o f e l e m e n t s o f a n o t h e r t y p e T2.

Page 74: CPlusPlus Templates The Complete Guide

2 . T h e s t a c k n o w u s e s a d e q u e a s a n i n t e r n a l c o n t a i n e r f o r t h e e l e m e n t s . A g a i n , t h i s i s a c o n s e q u e n c e o f t h e i m p l e m e n t a t i o n o f t h e n e w a s s i g n m e n t o p e r a t o r .

T h e i m p lem entati on of th e new as s i g nm ent op erator look s li k e th i s :

// basics/stack5assign.hpp template <typename T> template <typename T2> Stack<T>& Stack<T>::operator= (Stack<T2> const& op2) { if ((void*)this == (void*)&op2) { // assignment to itself? return *this; } Stack<T2> tmp(op2); // create a copy of the assigned stack elems.clear(); // remove existing elements while (!tmp.empty()) { // copy all elements elems.push_front(tmp.top()); tmp.pop(); } return *this; }

F i rs t let' s look at th e s yntax to defi ne a m em ber tem p late. I ns i de th e tem p late wi th tem p late p aram eter T, an i nner tem p late wi th tem p late p aram eter T2 i s defi ned:

template <typename T> template <typename T2> …

I ns i de th e m em ber fu ncti on you m ay ex p ect s i m p ly to acces s all neces s ary data for th e as s i g ned s tack op2. H owev er, th i s s tack h as a di fferent typ e (i f you i ns tanti ate a clas s tem p late for two di fferent typ es , you g et two di fferent typ es ), s o you are res tri cted to u s i ng th e p u bli c i nterface. I t follows th at th e only way to acces s th e elem ents i s by calli ng top(). H owev er, each elem ent h as to becom e a top elem ent, th en. T h u s , a cop y of op2 m u s t fi rs t be m ade, s o th at th e elem ents are tak en from th at cop y by calli ng pop(). B ecau s e top() retu rns th e las t elem ent p u s h ed onto th e s tack , we h av e to u s e a contai ner th at s u p p orts th e i ns erti on of elem ents at th e oth er end of th e collecti on. F or th i s reas on, we u s e a deq u e, wh i ch p rov i des push_front() to p u t an elem ent on th e oth er s i de of th e collecti on.

H av i ng th i s m em ber tem p late, you can now as s i g n a s tack of int s to a s tack of float s :

Page 75: CPlusPlus Templates The Complete Guide

Stack<int> intStack; // stack for ints Stack<float> floatStack; // stack for floats … floatStack = intStack; // OK: stacks have different types, // but int converts to float

O f cou rs e, th i s as s i g nm ent does not ch ang e th e typ e of th e s tack and i ts elem ents . A fter th e as s i g nm ent, th e elem ents of th e floatStack are s ti ll floats and th erefore pop() s ti ll retu rns a float.

I t m ay ap p ear th at th i s fu ncti on wou ld di s able typ e ch eck i ng s u ch th at you cou ld as s i g n a s tack wi th elem ents of any typ e, bu t th i s i s not th e cas e. T h e neces s ary typ e ch eck i ng occu rs wh en th e elem ent of th e (cop y of th e) s ou rce s tack i s m ov ed to th e des ti nati on s tack :

elems.push_front(tmp.top());

I f, for ex am p le, a s tack of s tri ng s g ets as s i g ned to a s tack of float s , th e com p i lati on of th i s li ne res u lts i n an error m es s ag e s tati ng th at th e s tri ng retu rned by tmp.top() cannot be p as s ed as an arg u m ent to elems.push_front() (th e m es s ag e v ari es dep endi ng on th e com p i ler, bu t th i s i s th e g i s t of wh at i s m eant):

Stack<std::string> stringStack; // stack of ints Stack<float> floatStack; // stack of floats … floatStack = stringStack; // ERROR: std::string doesn't convert to float

N ote th at a tem p late as s i g nm ent op erator does n' t rep lace th e defau lt as s i g nm ent op erator. F or as s i g nm ents of s tack s of th e s am e typ e, th e defau lt as s i g nm ent op erator i s s ti ll called.

A g ai n, you cou ld ch ang e th e i m p lem entati on to p aram eteri z e th e i nternal contai ner typ e:

// basics/stack6decl.hpp template <typename T, typename CONT = std::deque<T> > class Stack { private: CONT elems; // elements public: void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty();

Page 76: CPlusPlus Templates The Complete Guide

} // assign stack of elements of type T2 template <typename T2, typename CONT2> Stack<T,CONT>& operator= (Stack<T2,CONT2> const&); };

T h en th e tem p late as s i g nm ent op erator i s i m p lem ented li k e th i s :

// basics/stack6assign.hpp template <typename T, typename CONT> template <typename T2, typename CONT2> Stack<T,CONT>& Stack<T,CONT>::operator= (Stack<T2,CONT2> const& op2) { if ((void*)this == (void*)&op2) { // assignment to itself? return *this; } Stack<T2> tmp(op2); // create a copy of the assigned stack elems.clear(); // remove existing elements while (!tmp.empty()) { // copy all elements elems.push_front(tmp.top()); tmp.pop(); } return *this; }

R em em ber, for clas s tem p lates , only th os e m em ber fu ncti ons th at are called are i ns tanti ated. T h u s , i f you av oi d as s i g ni ng a s tack wi th elem ents of a di fferent typ e, you cou ld ev en u s e a v ector as an i nternal contai ner:

// stack for ints using a vector as an internal container Stack<int,std::vector<int> > vStack; … vStack.push(42); vStack.push(7); std::cout << vStack.pop() << std::endl;

B ecau s e th e as s i g nm ent op erator tem p late i s n' t neces s ary, no error m es s ag e of a m i s s i ng m em ber fu ncti on push_front() occu rs and th e p rog ram i s fi ne.

F or th e com p lete i m p lem entati on of th e las t ex am p le, s ee all th e fi les wi th a nam e th at s tarts wi th " stack6" i n th e s u bdi rectory basics. [1]

[1] D on' t be s u rp ri s ed i f you r com p i ler rep orts errors wi th th es e s am p le fi les . I n th e s am p les , we u s e alm os t ev ery i m p ortant tem p late featu re. T h u s , you need a com p i ler th at conform s clos ely to th e s tandard.

Page 77: CPlusPlus Templates The Complete Guide
Page 78: CPlusPlus Templates The Complete Guide

5.4 Template Template Parameters

I t can be u s efu l to allow a tem p late p aram eter i ts elf to be a clas s tem p late. A g ai n, ou r s tack clas s tem p late can be u s ed as an ex am p le.

T o u s e a di fferent i nternal contai ner for s tack s , th e ap p li cati on p rog ram m er h as to s p eci fy th e elem ent typ e twi ce. T h u s , to s p eci fy th e typ e of th e i nternal contai ner, you h av e to p as s th e typ e of th e contai ner an d th e typ e of i ts elem ents ag ai n:

Stack<int,std::vector<int> > vStack; // integer stack that uses a vector

U s i ng tem p late tem p late p aram eters allows you to declare th e Stack clas s tem p late by s p eci fyi ng th e typ e of th e contai ner wi th ou t res p eci fyi ng th e typ e of i ts elem ents :

stack<int,std::vector> vStack; // integer stack that uses a vector

T o do th i s you m u s t s p eci fy th e s econd tem p late p aram eter as a tem p late tem p late p aram eter. I n p ri nci p le, th i s look s as follows [2 ]:

[2 ] T h ere i s a p roblem wi th th i s v ers i on th at we ex p lai n i n a m i nu te. H owev er, th i s p roblem affects only th e defau lt v alu e std::deque. T h u s , we can i llu s trate th e g eneral featu res of tem p late tem p late p aram eters wi th th i s ex am p le.

// basics/stack7decl.hpp template <typename T, template <typename ELEM> class CONT = std::deque > class Stack { private: CONT<T> elems; // elements public: void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty(); } };

T h e di fference i s th at th e s econd tem p late p aram eter i s declared as bei ng a clas s

Page 79: CPlusPlus Templates The Complete Guide

tem p late:

template <typename ELEM> class CONT

T h e defau lt v alu e h as ch ang ed from std::deque<T> to std::deque. T h i s p aram eter h as to be a clas s tem p late, wh i ch i s i ns tanti ated for th e typ e th at i s p as s ed as th e fi rs t tem p late p aram eter:

CONT<T> elems;

T h i s u s e of th e fi rs t tem p late p aram eter for th e i ns tanti ati on of th e s econd tem p late p aram eter i s p arti cu lar to th i s ex am p le. I n g eneral, you can i ns tanti ate a tem p late tem p late p aram eter wi th any typ e i ns i de a clas s tem p late.

A s u s u al, i ns tead of typename you cou ld u s e th e k eyword class for tem p late p aram eters . H owev er, CONT i s u s ed to defi ne a clas s and m u s t be declared by u s i ng th e k eyword class. T h u s , th e followi ng i s fi ne:

template <typename T, template <class ELEM> class CONT = std::deque> // OK class Stack { … };

bu t th e followi ng i s not:

template <typename T, template <typename ELEM> typename CONT = std::deque> class Stack { // ERROR … };

B ecau s e th e tem p late p aram eter of th e tem p late tem p late p aram eter i s not u s ed, you can om i t i ts nam e:

template <typename T, template <typename> class CONT = std::deque > class Stack { … };

M em ber fu ncti ons m u s t be m odi fi ed accordi ng ly. T h u s , you h av e to s p eci fy th e s econd tem p late p aram eter as th e tem p late tem p late p aram eter. T h e s am e ap p li es to th e i m p lem entati on of th e m em ber fu ncti on. T h e push() m em ber fu ncti on, for ex am p le, i s i m p lem ented as follows :

Page 80: CPlusPlus Templates The Complete Guide

template <typename T, template <typename> class CONT> void Stack<T,CONT>::push (T const& elem) { elems.push_back(elem); // append copy of passed elem }

T em p late tem p late p aram eters for fu ncti on tem p lates are not allowed.

Template Template Argument Matching

I f you try to u s e th e new v ers i on of Stack, you g et an error m es s ag e s ayi ng th at th e defau lt v alu e std::deque i s not com p ati ble wi th th e tem p late tem p late p aram eter CONT. T h e p roblem i s th at a tem p late tem p late arg u m ent m u s t be a tem p late wi th p aram eters th at ex ac tly m atch th e p aram eters of th e tem p late tem p late p aram eter i t s u bs ti tu tes . D efau lt tem p late arg u m ents of tem p late tem p late arg u m ents are not cons i dered, s o th at a m atch cannot be ach i ev ed by leav i ng ou t arg u m ents th at h av e defau lt v alu es .

T h e p roblem i n th i s ex am p le i s th at th e std::deque tem p late of th e s tandard li brary h as m ore th an one p aram eter: T h e s econd p aram eter (wh i ch des cri bes a s o-called alloc ator ) h as a defau lt v alu e, bu t th i s i s not cons i dered wh en m atch i ng std::deque to th e CONT p aram eter.

T h ere i s a work arou nd, h owev er. W e can rewri te th e clas s declarati on s o th at th e CONT p aram eter ex p ects contai ners wi th two tem p late p aram eters :

template <typename T, template <typename ELEM, typename ALLOC = std::allocator<ELEM> > class CONT = std::deque> class Stack { private: CONT<T> elems; // elements … };

A g ai n, you can om i t ALLOC becau s e i t i s not u s ed.

T h e fi nal v ers i on of ou r Stack tem p late (i nclu di ng m em ber tem p lates for as s i g nm ents of s tack s of di fferent elem ent typ es ) now look s as follows :

// basics/stack8.hpp #ifndef STACK_HPP #define STACK_HPP #include <deque> #include <stdexcept>

Page 81: CPlusPlus Templates The Complete Guide

#include <allocator> template <typename T, template <typename ELEM, typename = std::allocator<ELEM> > class CONT = std::deque> class Stack { private: CONT<T> elems; // elements public: void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty(); } // assign stack of elements of type T2 template<typename T2, template<typename ELEM2, typename = std::allocator<ELEM2> >class CONT2> Stack<T,CONT>& operator= (Stack<T2,CONT2> const&); }; template <typename T, template <typename,typename> class CONT> void Stack<T,CONT>::push (T const& elem) { elems.push_back(elem); // append copy of passed elem } template<typename T, template <typename,typename> class CONT> void Stack<T,CONT>::pop () { if (elems.empty()) { throw std::out_of_range("Stack<>::pop(): empty stack"); } elems.pop_back(); // remove last element } template <typename T, template <typename,typename> class CONT> T Stack<T,CONT>::top () const { if (elems.empty()) { throw std::out_of_range("Stack<>::top(): empty stack"); } return elems.back(); // return copy of last element } template <typename T, template <typename,typename> class CONT> template <typename T2, template <typename,typename> class CONT2> Stack<T,CONT>& Stack<T,CONT>::operator= (Stack<T2,CONT2> const& op2) { if ((void*)this == (void*)&op2) { // assignment to itself? return *this; } Stack<T2> tmp(op2); // create a copy of the assigned stack

Page 82: CPlusPlus Templates The Complete Guide

elems.clear(); // remove existing elements while (!tmp.empty()) { // copy all elements elems.push_front(tmp.top()); tmp.pop(); } return *this; } #endif // STACK_HPP

T h e followi ng p rog ram u s es all featu res of th i s fi nal v ers i on:

// basics/stack8test.cpp #include <iostream> #include <string> #include <cstdlib> #include <vector> #include "stack8.hpp" int main() { try { Stack<int> intStack; // stack of ints Stack<float> floatStack; // stack of floats // manipulate int stack intStack.push(42); intStack.push(7); // manipulate float stack floatStack.push(7.7); // assign stacks of different type floatStack = intStack; // print float stack std::cout << floatStack.top() << std::endl; floatStack.pop(); std::cout << floatStack.top() << std::endl; floatStack.pop(); std::cout << floatStack.top() << std::endl; floatStack.pop(); } catch (std::exception const& ex) { std::cerr << "Exception: " << ex.what() << std::endl; } // stack for ints using a vector as an internal container Stack<int,std::vector> vStack; … vStack.push(42); vStack.push(7); std::cout << vStack.top() << std::endl; vStack.pop(); }

Page 83: CPlusPlus Templates The Complete Guide

T h e p rog ram h as th e followi ng ou tp u t:

7 42 Exception: Stack<>::top(): empty stack 7

N ote th at tem p late tem p late p aram eters are one of th e m os t recent featu res req u i red for com p i lers to conform to th e s tandard. T h u s , th i s p rog ram i s a g ood ev alu ati on of th e conform i ty of you r com p i ler reg ardi ng tem p late featu res .

F or fu rth er di s cu s s i ons and ex am p les of tem p late tem p late p aram eters , s ee Secti on 8 .2.3 on p ag e 102 and Secti on 15 .1.6 on p ag e 25 9 .

Page 84: CPlusPlus Templates The Complete Guide

5.5 Zero Initialization

F or fu ndam ental typ es s u ch as int , double, or p oi nter typ es , th ere i s no defau lt cons tru ctor th at i ni ti ali z es th em wi th a u s efu l defau lt v alu e. I ns tead, any noni ni ti ali z ed local v ari able h as an u ndefi ned v alu e:

void foo() { int x; // x has undefined value int* ptr; // ptr points to somewhere (instead of nowhere) }

N ow i f you wri te tem p lates and want to h av e v ari ables of a tem p late typ e i ni ti ali z ed by a defau lt v alu e, you h av e th e p roblem th at a s i m p le defi ni ti on does n' t do th i s for bu i lt-i n typ es :

template <typename T> void foo() { T x; // x has undefined value if T is built-in type }

F or th i s reas on, i t i s p os s i ble to call ex p li ci tly a defau lt cons tru ctor for bu i lt-i n typ es th at i ni ti ali z es th em wi th z ero (or false for bool). T h at i s , int() yi elds z ero. A s a cons eq u ence you can ens u re p rop er defau lt i ni ti ali z ati on ev en for bu i lt-i n typ es by wri ti ng th e followi ng :

template <typename T> void foo() { T x = T(); // x is zero (or false)ifT is a built-in type }

T o m ak e s u re th at a m em ber of a clas s tem p late, for wh i ch th e typ e i s p aram eteri z ed, g ets i ni ti ali z ed, you h av e to defi ne a defau lt cons tru ctor th at u s es an i ni ti ali z er li s t to i ni ti ali z e th e m em ber:

template <typename T> class MyClass { private: T x; public: MyClass() : x() { // ensures that x is initialized even for built-in types } …

Page 85: CPlusPlus Templates The Complete Guide

};

Page 86: CPlusPlus Templates The Complete Guide

5.6 Using String Literals as Arguments for Function Templates

P as s i ng s tri ng li teral arg u m ents for reference p aram eters of fu ncti on tem p lates s om eti m es fai ls i n a s u rp ri s i ng way. C ons i der th e followi ng ex am p le:

// basics/max5.cpp #include <string> // note: reference parameters template <typename T> inline T const& max (T const& a, T const& b) { return a < b ? b : a; } int main() { std::string s; ::max("apple","peach"); // OK: same type ::max("apple","tomato"); // ERROR: different types ::max("apple",s); // ERROR: different types }

T h e p roblem i s th at s tri ng li terals h av e di fferent array typ es dep endi ng on th ei r leng th s . T h at i s , "apple" and "peach" h av e typ e char const[6] wh ereas "tomato" h as typ e char const[7]. O nly th e fi rs t call i s p os s i ble becau s e th e tem p late ex p ects both p aram eters to h av e th e s am e typ e. H owev er, i f you declare nonreference p aram eters , you can s u bs ti tu te th em wi th s tri ng li terals of di fferent s i z e:

// basics/max6.cpp #include <string> // note: nonreference parameters template <typename T> inline T max (T a, T b) { return a < b ? b : a; } int main() { std::string s; ::max("apple","peach"); // OK: same type ::max("apple","tomato"); // OK: decays to same type ::max("apple",s); // ERROR: different types }

Page 87: CPlusPlus Templates The Complete Guide

T h e ex p lanati on for th i s beh av i or i s th at du ri ng arg u m ent dedu cti on array-to-p oi nter conv ers i on (often called d ec ay ) occu rs only i f th e p aram eter does not h av e a reference typ e. T h i s i s dem ons trated by th e followi ng p rog ram :

// basics/refnonref.cpp #include <typeinfo> #include <iostream> template <typename T> void ref (T const& x) { std::cout << "x in ref(T const&): " << typeid(x).name() << '\n'; } template <typename T> void nonref (T x) { std::cout << "x in nonref(T): " << typeid(x).name() << '\n'; } int main() { ref("hello"); nonref("hello"); }

T h e ex am p le p as s es a s tri ng li teral to fu ncti on tem p lates th at declare th ei r p aram eter to be a reference or nonreference res p ecti v ely. B oth fu ncti on tem p lates u s e th e typeid op erator to p ri nt th e typ e of th e i ns tanti ated p aram eters . T h e typeid op erator retu rns an lv alu e of typ e std::type_info , wh i ch encap s u lates a rep res entati on of th e typ e of th e ex p res s i on p as s ed to th e typeid op erator. T h e m em ber fu ncti on name() of std::type_info i s i ntended to retu rn a h u m an-readable tex t rep res entati on of th e latter typ e. T h e C + + s tandard does n' t actu ally s ay th at name() m u s t retu rn s om eth i ng m eani ng fu l, bu t on g ood C + + i m p lem entati ons , you s h ou ld g et a s tri ng th at g i v es a g ood des cri p ti on of th e typ e of th e ex p res s i on p as s ed to typeid (wi th s om e i m p lem entati ons th i s s tri ng i s man g led , bu t a d eman g ler i s av ai lable to tu rn i t i nto h u m an-readable tex t). F or ex am p le, th e ou tp u t m i g h t be as follows :

x in ref(T const&): char [6] x in nonref(T): const char *

I f you encou nter a p roblem i nv olv i ng a m i s m atch between an array of ch aracters and a p oi nter to ch aracters , you m i g h t h av e s tu m bled on th i s s om ewh at s u rp ri s i ng p h enom enon. [3 ] T h ere i s u nfortu nately no g eneral s olu ti ons to addres s

Page 88: CPlusPlus Templates The Complete Guide

th i s p roblem . D ep endi ng on th e contex t, you can [3 ] I n fact, th i s i s th e reas on th at you cannot create a p ai r of v alu es i ni ti ali z ed wi th s tri ng li terals u s i ng th e ori g i nal C + + s tandard li brary (s ee [Standard9 8 ] ): std::make_pair("key","value") // ERROR according to [Standard98]

T h i s was fi x ed wi th th e fi rs t tech ni cal corri g endu m by rep laci ng th e reference p aram eters of make_pair() by nonreference p aram eters (s ee [Standard02] ).

• u s e nonreferences i ns tead of references (h owev er, th i s can lead to u nneces s ary cop yi ng )

• ov erload u s i ng both reference and nonreference p aram eters (h owev er, th i s m i g h t lead to am bi g u i ti es ; s ee Secti on B .2.2 on p ag e 4 9 2)

• ov erload wi th concrete typ es (s u ch as std::string) • ov erload wi th array typ es , for ex am p le: • • template <typename T, int N, int M>

• T const* max (T const (&a)[N], T const (&b)[M]) • {

• return a < b ? b : a; }

• force ap p li cati on p rog ram m ers to u s e ex p li ci t conv ers i ons

I n th i s ex am p le i t i s bes t to ov erload max() for s tri ng s (s ee Secti on 2.4 on p ag e 16). T h i s i s neces s ary anyway becau s e wi th ou t ov erloadi ng i n cas es wh ere th e call to max() i s v ali d for s tri ng li terals , th e op erati on th at i s p erform ed i s a p oi nter com p ari s on: a<bcom p ares th e addres s es of th e two s tri ng li terals and h as noth i ng to do wi th lex i cog rap h i cal order. T h i s i s anoth er reas on wh y i t i s u s u ally p referable to u s e a s tri ng clas s s u ch as std::string i ns tead of C -s tyle s tri ng s .

See Secti on 11.1 on p ag e 168 for detai ls .

Page 89: CPlusPlus Templates The Complete Guide

5.7 Summary

• T o acces s a typ e nam e th at dep ends on a tem p late p aram eter, you h av e to q u ali fy th e nam e wi th a leadi ng typename.

• N es ted clas s es and m em ber fu ncti ons can als o be tem p lates . O ne ap p li cati on i s th e abi li ty to i m p lem ent g eneri c op erati ons wi th i nternal typ e conv ers i ons . H owev er, typ e ch eck i ng s ti ll occu rs .

• T em p late v ers i ons of as s i g nm ent op erators don' t rep lace defau lt as s i g nm ent op erators .

• Y ou can als o u s e clas s tem p lates as tem p late p aram eters , as s o-called template template par ameter s.

• T em p late tem p late arg u m ents m u s t m atch ex actly. D efau lt tem p late arg u m ents of tem p late tem p late arg u m ents are i g nored.

• B y ex p li ci tly calli ng a defau lt cons tru ctor, you can m ak e s u re th at v ari ables and m em bers of tem p lates are i ni ti ali z ed by a defau lt v alu e ev en i f th ey are i ns tanti ated wi th a bu i lt-i n typ e.

• F or s tri ng li terals th ere i s an array-to-p oi nter conv ers i on du ri ng arg u m ent dedu cti on i f and only i f th e p aram eter i s not a reference.

Page 90: CPlusPlus Templates The Complete Guide

Chapter 6. Using Templates in Practice

T em p late code i s a li ttle di fferent from ordi nary code. I n s om e ways tem p lates li e s om ewh ere between m acros and ordi nary (nontem p late) declarati ons . A lth ou g h th i s m ay be an ov ers i m p li fi cati on, i t h as cons eq u ences not only for th e way we wri te alg ori th m s and data s tru ctu res u s i ng tem p lates , bu t als o for th e day-to-day log i s ti cs of ex p res s i ng and analyz i ng p rog ram s i nv olv i ng tem p lates .

I n th i s ch ap ter we addres s s om e of th es e p racti cali ti es wi th ou t neces s ari ly delv i ng i nto th e tech ni cal detai ls th at u nderli e th em . M any of th es e detai ls are ex p lored i n C h ap ter 10. T o k eep th e di s cu s s i on s i m p le, we as s u m e th at ou r C + + com p i lati on s ys tem s cons i s t of fai rly tradi ti onal com p i lers and li nk ers (C + + s ys tem s th at don' t fall i n th i s categ ory are q u i te rare).

Page 91: CPlusPlus Templates The Complete Guide

6.1 The Inclusion Model

T h ere are s ev eral ways to org ani z e tem p late s ou rce code. T h i s s ecti on p res ents th e m os t p op u lar ap p roach as of th e ti m e of th i s wri ti ng : th e i nclu s i on m odel.

6.1.1 Linker Errors

M os t C and C + + p rog ram m ers org ani z e th ei r nontem p late code larg ely as follows :

• C las s es and oth er typ es are enti rely p laced i n head er f i les. T yp i cally, th i s i s a fi le wi th a .hpp (or .H, .h, .hh , .hxx) fi lenam e ex tens i on.

• F or g lobal v ari ables and (noni nli ne) fu ncti ons , only a declarati on i s p u t i n a h eader fi le, and th e defi ni ti on g oes i nto a s o-called d ot-C f i le. T yp i cally, th i s i s a fi le wi th a .cpp (or .C , .c , .cc, or .hxx) fi lenam e ex tens i on.

T h i s work s well: I t m ak es th e needed typ e defi ni ti on eas i ly av ai lable th rou g h ou t th e p rog ram and av oi ds du p li cate defi ni ti on errors on v ari ables and fu ncti ons from th e li nk er.

W i th th es e conv enti ons i n m i nd, a com m on error abou t wh i ch beg i nni ng tem p late p rog ram m ers com p lai n i s i llu s trated by th e followi ng (erroneou s ) li ttle p rog ram . A s u s u al for " ordi nary code, " we declare th e tem p late i n a h eader fi le:

// basics/myfirst.hpp #ifndef MYFIRST_HPP #define MYFIRST_HPP // declaration of template template <typename T> void print_typeof (T const&); #endif // MYFIRST_HPP

print_typeof() i s th e declarati on of a s i m p le au x i li ary fu ncti on th at p ri nts s om e typ e i nform ati on. T h e i m p lem entati on of th e fu ncti on i s p laced i n a dot-C fi le:

// basics/myfirst.cpp #include <iostream> #include <typeinfo> #include "myfirst.hpp"

Page 92: CPlusPlus Templates The Complete Guide

// implementation/definition of template template <typename T> void print_typeof (T const& x) { std::cout << typeid(x).name() << std::endl; }

T h e ex am p le u s es th e typeid op erator to p ri nt a s tri ng th at des cri bes th e typ e of th e ex p res s i on p as s ed to i t (s ee Secti on 5 .6 on p ag e 5 8 ).

F i nally, we u s e th e tem p late i n anoth er dot-C fi le, i nto wh i ch ou r tem p late declarati on i s #included:

// basics/myfirstmain.cpp #include "myfirst.hpp" // use of the template int main() { double ice = 3.0; print_typeof(ice); // call function template for type double }

A C + + com p i ler wi ll m os t li k ely accep t th i s p rog ram wi th ou t any p roblem s , bu t th e li nk er wi ll p robably rep ort an error, i m p lyi ng th at th ere i s no defi ni ti on of th e fu ncti on print_typeof().

T h e reas on for th i s error i s th at th e defi ni ti on of th e fu ncti on tem p late print_typeof() h as not been i ns tanti ated. I n order for a tem p late to be i ns tanti ated, th e com p i ler m u s t k now wh i ch defi ni ti on s h ou ld be i ns tanti ated and for wh at tem p late arg u m ents i t s h ou ld be i ns tanti ated. U nfortu nately, i n th e p rev i ou s ex am p le, th es e two p i eces of i nform ati on are i n fi les th at are com p i led s ep arately. T h erefore, wh en ou r com p i ler s ees th e call to print_typeof() bu t h as no defi ni ti on i n s i g h t to i ns tanti ate th i s fu ncti on for double, i t j u s t as s u m es th at s u ch a defi ni ti on i s p rov i ded els ewh ere and creates a reference (for th e li nk er to res olv e) to th at defi ni ti on. O n th e oth er h and, wh en th e com p i ler p roces s es th e fi le myfirst.cpp , i t h as no i ndi cati on at th at p oi nt th at i t m u s t i ns tanti ate th e tem p late defi ni ti on i t contai ns for s p eci fi c arg u m ents .

6.1.2 Templates in Header Files

T h e com m on s olu ti on to th e p rev i ou s p roblem i s to u s e th e s am e ap p roach th at we wou ld tak e wi th m acros or wi th i nli ne fu ncti ons : W e i nclu de th e defi ni ti ons of a tem p late i n th e h eader fi le th at declares th at tem p late. F or ou r ex am p le, we can do th i s by addi ng

#include "myfirst.cpp"

Page 93: CPlusPlus Templates The Complete Guide

at th e end of myfirst.hpp or by i nclu di ng myfirst.cpp i n ev ery dot-C fi le th at u s es th e tem p late. A th i rd way, of cou rs e, i s to do away enti rely wi th myfirst.cpp and rewri te myfirst.hpp s o th at i t contai ns all tem p late declarati ons an d tem p late defi ni ti ons :

// basics/myfirst2.hpp #ifndef MYFIRST_HPP #define MYFIRST_HPP #include <iostream> #include <typeinfo> // declaration of template template <typename T> void print_typeof (T const&); // implementation/definition of template template <typename T> void print_typeof (T const& x) { std::cout << typeid(x).name() << std::endl; } #endif // MYFIRST_HPP

T h i s way of org ani z i ng tem p lates i s called th e i n c lu si on mod el. W i th th i s i n p lace, you s h ou ld fi nd th at ou r p rog ram now correctly com p i les , li nk s , and ex ecu tes .

T h ere are a few obs erv ati ons we can m ak e at th i s p oi nt. T h e m os t notable i s th at th i s ap p roach h as cons i derably i ncreas ed th e cos t of i nclu di ng th e h eader fi le myfirst.hpp. I n th i s ex am p le, th e cos t i s not th e res u lt of th e s i z e of th e tem p late defi ni ti on i ts elf, bu t th e res u lt of th e fact th at we m u s t als o i nclu de th e h eaders u s ed by th e defi ni ti on of ou r tem p late—i n th i s cas e <iostream> and <typeinfo>. Y ou m ay fi nd th at th i s am ou nts to tens of th ou s ands of li nes of code becau s e h eaders li k e <iostream> contai n s i m i lar tem p late defi ni ti ons .

T h i s i s a real p roblem i n p racti ce becau s e i t cons i derably i ncreas es th e ti m e needed by th e com p i ler to com p i le s i g ni fi cant p rog ram s . W e wi ll th erefore ex am i ne s om e p os s i ble ways to ap p roach th i s p roblem i n u p com i ng s ecti ons . H owev er, real-world p rog ram s q u i ck ly end u p tak i ng h ou rs to com p i le and li nk (we h av e been i nv olv ed i n s i tu ati ons i n wh i ch i t li terally took days to bu i ld a p rog ram com p letely from i ts s ou rce code).

D es p i te th i s bu i ld-ti m e i s s u e, we do recom m end followi ng th i s i nclu s i on m odel to org ani z e you r tem p lates wh en p os s i ble. W e ex am i ne two alternati v es , bu t i n ou r op i ni on th ei r eng i neeri ng defi ci enci es are m ore s eri ou s th an th e bu i ld-ti m e i s s u e di s cu s s ed h ere. T h ey m ay h av e oth er adv antag es not di rectly related to th e

Page 94: CPlusPlus Templates The Complete Guide

eng i neeri ng as p ects of s oftware dev elop m ent, h owev er.

A noth er (m ore s u btle) obs erv ati on abou t th e i nclu s i on ap p roach i s th at noni nli ne fu ncti on tem p lates are di s ti nct from i nli ne fu ncti ons and m acros i n an i m p ortant way: T h ey are not ex p anded at th e call s i te. I ns tead, wh en th ey are i ns tanti ated, th ey create a new cop y of a fu ncti on. B ecau s e th i s i s an au tom ati c p roces s , a com p i ler cou ld end u p creati ng two cop i es i n two di fferent fi les , and s om e li nk ers cou ld i s s u e errors wh en th ey fi nd two di s ti nct defi ni ti ons for th e s am e fu ncti on. I n th eory, th i s s h ou ld not be a concern of ou rs : I t i s a p roblem for th e C + + com p i lati on s ys tem to accom m odate. I n p racti ce, th i ng s work well m os t of th e ti m e, and we don' t need to deal wi th th i s i s s u e at all. F or larg e p roj ects th at create th ei r own li brary of code, h owev er, p roblem s occas i onally s h ow u p . A di s cu s s i on of i ns tanti ati on s ch em es i n C h ap ter 10 and a clos e s tu dy of th e docu m entati on th at cam e wi th th e C + + trans lati on s ys tem (com p i ler) s h ou ld h elp addres s th es e p roblem s .

F i nally, we need to p oi nt ou t th at wh at ap p li es to th e ordi nary fu ncti on tem p late i n ou r ex am p le als o ap p li es to m em ber fu ncti ons and s tati c data m em bers of clas s tem p lates , as well as to m em ber fu ncti on tem p lates .

Page 95: CPlusPlus Templates The Complete Guide

6.2 Explicit Instantiation

T h e i nclu s i on m odel ens u res th at all th e needed tem p lates are i ns tanti ated. T h i s h ap p ens becau s e th e C + + com p i lati on s ys tem au tom ati cally g enerates th os e i ns tanti ati ons as th ey are needed. T h e C + + s tandard als o offers a cons tru ct to i ns tanti ate tem p lates m anu ally: th e ex pli c i t i n stan ti ati on d i r ec ti v e.

6.2.1 Example of Explicit Instantiation

T o i llu s trate m anu al i ns tanti ati on, let' s rev i s i t ou r ori g i nal ex am p le th at leads to a li nk er error (s ee p ag e 62). T o av oi d th i s error we add th e followi ng fi le to ou r p rog ram :

// basics/myfirstinst.cpp #include "myfirst.cpp" // explicitly instantiate print_typeof() for type double template void print_typeof<double>(double const&);

T h e ex p li ci t i ns tanti ati on di recti v e cons i s ts of th e k eyword template followed by th e fu lly s u bs ti tu ted declarati on of th e enti ty we want to i ns tanti ate. I n ou r ex am p le, we do th i s wi th an ordi nary fu ncti on, bu t i t cou ld be a m em ber fu ncti on or a s tati c data m em ber. F or ex am p le:

// explicitly instantiate a constructor of MyClass<> for int template MyClass<int>::MyClass(); // explicitly instantiate a function template max() for int template int const& max (int const&, int const&);

Y ou can als o ex p li ci tly i ns tanti ate a clas s tem p late, wh i ch i s s h ort for req u es ti ng th e i ns tanti ati on of all i ts i ns tanti atable m em bers . T h i s ex clu des m em bers th at were p rev i ou s ly s p eci ali z ed as well as th os e th at were already i ns tanti ated:

// explicitly instantiate class Stack<> for int: template class Stack<int>; // explicitly instantiate some member functions of Stack<> for strings: template Stack<std::string>::Stack(); template void Stack<std::string>::push(std::string const&); template std::string Stack<std::string>::top(); // ERROR: can't explicitly instantiate a member function of a // class that was itself explicitly instantiated: template Stack<int>::Stack();

Page 96: CPlusPlus Templates The Complete Guide

T h ere s h ou ld be, at m os t, one ex p li ci t i ns tanti ati on of each di s ti nct enti ty i n a p rog ram . I n oth er words , you cou ld ex p li ci tly i ns tanti ate both print_typeof<int> and print_typeof<double> , bu t each di recti v e s h ou ld ap p ear only once i n a p rog ram . N ot followi ng th i s ru le u s u ally res u lts i n li nk er errors th at rep ort du p li cate defi ni ti ons of th e i ns tanti ated enti ti es .

M anu al i ns tanti ati on h as a clear di s adv antag e: W e m u s t carefu lly k eep track of wh i ch enti ti es to i ns tanti ate. F or larg e p roj ects th i s q u i ck ly becom es an ex ces s i v e bu rden; h ence we do not recom m end i t. W e h av e work ed on s ev eral p roj ects th at i ni ti ally u nderes ti m ated th i s bu rden, and we cam e to reg ret ou r deci s i on as th e code m atu red.

H owev er, ex p li ci t i ns tanti ati on als o h as a few adv antag es becau s e th e i ns tanti ati on can be tu ned to th e needs of th e p rog ram . C learly, th e ov erh ead of larg e h eaders i s av oi ded. T h e s ou rce code of tem p late defi ni ti on can be k ep t h i dden, bu t th en no addi ti onal i ns tanti ati ons can be created by a cli ent p rog ram . F i nally, for s om e ap p li cati ons i t can be u s efu l to control th e ex act locati on (th at i s , th e obj ect fi le) of a tem p late i ns tance. W i th au tom ati c i ns tanti ati on, th i s m ay not be p os s i ble (s ee C h ap ter 10 for detai ls ).

6.2.2 Combining the Inclusion Model and Explicit Instantiation

T o k eep th e deci s i on op en wh eth er to u s e th e i nclu s i on m odel or ex p li ci t i ns tanti ati on, we can p rov i de th e declarati on and th e defi ni ti on of tem p lates i n two di fferent fi les . I t i s com m on p racti ce to h av e both fi les nam ed as h eader fi les (u s i ng an ex tens i on ordi nari ly u s ed for fi les th at are i ntended to be #included), and i t i s p robably wi s e to s ti ck to th i s conv enti on. (T h u s , myfirst.cpp of ou r m oti v ati ng ex am p le becom es myfirstdef.hpp , wi th p rep roces s or g u ards arou nd th e code i ns erted.) F i g u re 6.1 dem ons trates th i s for a Stack<> clas s tem p late.

Figu r e 6 . 1 . S e p a r a t io n o f t e m p l a t e d e c l a r a t i o n a n d d e f in it io n

Page 97: CPlusPlus Templates The Complete Guide

N ow i f we want to u s e th e i nclu s i on m odel, we can s i m p ly i nclu de th e defi ni ti on h eader fi le stackdef.hpp. A lternati v ely, i f we want to i ns tanti ate th e tem p lates ex p li ci tly, we can i nclu de th e declarati on h eader stack.hpp and p rov i de a dot-C fi le wi th th e neces s ary ex p li ci t i ns tanti ati on di recti v es (s ee F i g u re 6.2).

Figu r e 6 . 2 . E x p l ic it in s t a n t ia t io n w it h t w o t e m p l a t e h e a d e r f il e s

Page 98: CPlusPlus Templates The Complete Guide
Page 99: CPlusPlus Templates The Complete Guide

6.3 The Separation Model

B oth ap p roach es adv ocated i n th e p rev i ou s s ecti ons work well and conform enti rely to th e C + + s tandard. H owev er, th i s s am e s tandard als o p rov i des th e alternati v e m ech ani s m of ex por ti n g tem p lates . T h i s ap p roach i s s om eti m es called th e C + + tem p late separ ati on mod el.

6.3.1 The Keyword export

I n p ri nci p le, i t i s q u i te s i m p le to m ak e u s e of th e export faci li ty: D efi ne th e tem p late i n j u s t one fi le, and m ark th at defi ni ti on and all i ts nondefi ni ng declarati ons wi th th e k eyword export. F or th e ex am p le i n th e p rev i ou s s ecti on, th i s res u lts i n th e followi ng fu ncti on tem p late declarati on:

// basics/myfirst3.hpp #ifndef MYFIRST_HPP #define MYFIRST_HPP // declaration of template export template <typename T> void print_typeof (T const&); #endif // MYFIRST_HPP

E x p orted tem p lates can be u s ed wi th ou t th ei r defi ni ti on bei ng v i s i ble. I n oth er words , th e p oi nt wh ere a tem p late i s bei ng u s ed and th e p oi nt wh ere i t i s defi ned can be i n two di fferent trans lati on u ni ts . I n ou r ex am p le, th e fi le myfirst.hpp now contai ns only th e d ec lar ati on of th e m em ber fu ncti ons of th e clas s tem p late, and th i s i s s u ffi ci ent to u s e th os e m em bers . C om p ari ng th i s wi th th e ori g i nal code th at was tri g g eri ng li nk er errors , we h ad to add only one export k eyword i n ou r code and th i ng s now work j u s t fi ne.

W i th i n a p rep roces s ed fi le (th at i s , wi th i n a trans lati on u ni t), i t i s s u ffi ci ent to m ark th e fi rs t declarati on of a tem p late wi th export. L ater redeclarati ons , i nclu di ng defi ni ti ons , i m p li ci tly k eep th at attri bu te. T h i s i s wh y myfirst.cpp does not need to be m odi fi ed i n ou r ex am p le. T h e defi ni ti ons i n th i s fi le are i m p li ci tly ex p orted becau s e th ey were s o declared i n th e #included h eader fi le. O n th e oth er h and, i t i s p erfectly accep table to p rov i de redu ndant export k eywords on tem p late defi ni ti ons , and doi ng s o m ay i m p rov e th e readabi li ty of th e code.

T h e k eyword export really ap p li es to fu ncti on tem p lates , m em ber fu ncti ons of

Page 100: CPlusPlus Templates The Complete Guide

clas s tem p lates , m em ber fu ncti on tem p lates , and s tati c data m em bers of clas s tem p lates . export can als o be ap p li ed to a clas s tem p late declarati on. I t i m p li es th at ev ery one of i ts ex p ortable m em bers i s ex p orted, bu t clas s tem p lates th em s elv es are not actu ally ex p orted (h ence, th ei r defi ni ti ons s ti ll ap p ear i n h eader fi les ). Y ou can s ti ll h av e i m p li ci tly or ex p li ci tly defi ned i nli ne m em ber fu ncti ons . H owev er, th es e i nli ne fu ncti ons are not ex p orted:

export template <typename T> class MyClass { public: void memfun1(); // exported void memfun2() { // not exported because implicitly inline … } void memfun3(); // not exported because explicitly inline … }; template <typename T> inline void MyClass<T>::memfun3 () { … }

H owev er, note th at th e k eyword export cannot be com bi ned wi th inline and m u s t always p recede th e k eyword template. T h e followi ng i s i nv ali d:

template <typename T> class Invalid { public: export void wrong(T); // ERROR: export not followed by template }; export template<typename T> // ERROR: both export and inline inline void Invalid<T>::wrong(T) { } export inline T const& max (T const&a, T const& b) { // ERROR: both export and inline return a < b ? b : a; }

6.3.2 Limitations of the Separation Model

A t th i s p oi nt i t i s reas onable to wonder wh y we' re s ti ll adv ocati ng th e i nclu s i on ap p roach wh en ex p orted tem p lates s eem to offer j u s t th e ri g h t m ag i c to m ak e th i ng s work . T h ere are a few di fferent as p ects to th i s ch oi ce.

F i rs t, ev en fou r years after th e s tandard cam e ou t, only one com p any h as actu ally i m p lem ented s u p p ort for th e export k eyword. [1] T h erefore, ex p eri ence wi th th i s

Page 101: CPlusPlus Templates The Complete Guide

featu re i s not as wi des p read as oth er C + + featu res . C learly, th i s als o m eans th at at th i s p oi nt ex p eri ence wi th ex p orted tem p lates i s fai rly li m i ted, and all ou r obs erv ati ons wi ll u lti m ately h av e to be tak en wi th a g rai n of s alt. I t i s p os s i ble th at s om e of ou r m i s g i v i ng s wi ll be addres s ed i n th e fu tu re (and we s h ow h ow to p rep are for th at ev entu ali ty).

[1] A s far as we k now, E di s on D es i g n G rou p , I nc. (E D G ) i s s ti ll th at com p any (s ee [E D G ] ). T h ei r tech nolog y i s av ai lable th rou g h oth er v endors , h owev er.

Second, alth ou g h export m ay s eem q u as i -m ag i cal, i t i s not ac tu ally m ag i cal. U lti m ately, th e i ns tanti ati on p roces s h as to deal wi th both th e p lace wh ere a tem p late i s i ns tanti ated and th e p lace wh ere i ts defi ni ti on ap p ears . H ence, alth ou g h th es e two s eem neatly decou p led i n th e s ou rce code, th ere i s an i nv i s i ble cou p li ng th at th e s ys tem es tabli s h es beh i nd th e s cenes . T h i s m ay m ean, for ex am p le, th at i f th e fi le contai ni ng th e defi ni ti on ch ang es , both th at fi le and all th e fi les th at i ns tanti ate th e tem p lates i n th at fi le m ay need to be recom p i led. T h i s i s not s u bs tanti ally di fferent from th e i nclu s i on ap p roach , bu t i t i s no long er obv i ou s ly v i s i ble i n th e s ou rce code. A s a cons eq u ence, dep endency m anag em ent tools (s u ch as th e p op u lar make and nmake p rog ram s ) th at u s e tradi ti onal s ou rce-bas ed tech ni q u es no long er work . I t als o m eans th at q u i te a few bi ts of ex tra p roces s i ng by th e com p i ler are needed to k eep all th e book k eep i ng s trai g h t; and i n th e end, th e bu i ld ti m es m ay not be better th an th os e of th e i nclu s i on ap p roach .

F i nally, ex p orted tem p lates m ay lead to s u rp ri s i ng s em anti c cons eq u ences , th e detai ls of wh i ch are ex p lai ned i n C h ap ter 10.

A com m on m i s concep ti on i s th at th e export m ech ani s m offers th e p otenti al of bei ng able to s h i p li brari es of tem p lates wi th ou t rev eali ng th e s ou rce code for th ei r defi ni ti ons (j u s t li k e li brari es of nontem p late enti ti es ). [2 ] T h i s i s a m i s concep ti on i n th e s ens e th at h i di ng code i s not a lang u ag e i s s u e: I t wou ld be eq u ally p os s i ble to p rov i de a m ech ani s m to h i de i nclu ded tem p late defi ni ti ons as to h i de ex p orted tem p late defi ni ti ons . A lth ou g h th i s m ay be feas i ble (th e cu rrent i m p lem entati ons do not s u p p ort th i s m odel), i t u nfortu nately creates new ch alleng es i n deali ng wi th tem p late com p i lati on errors th at need to refer to th e h i dden s ou rce code.

[2 ] N ot ev erybody cons i ders th i s c losed -sou r c e ap p roach a p lu s .

6.3.3 Preparing for the Separation Model

O ne work able i dea i s to p rep are ou r s ou rces i n s u ch a way th at we can eas i ly s wi tch between th e i nclu s i on and ex p ort m odels u s i ng a h arm les s dos e of

Page 102: CPlusPlus Templates The Complete Guide

p rep roces s or di recti v es . H ere i s h ow i t can be done for ou r s i m p le ex am p le:

// basics/myfirst4.hpp #ifndef MYFIRST_HPP #define MYFIRST_HPP // use export if USE_EXPORT is defined #if defined(USE_EXPORT) #define EXPORT export #else #define EXPORT #endif // declaration of template EXPORT template <typename T> void print_typeof (T const&); // include definition if USE_EXPORT is not defined #if !defined(USE_EXPORT) #include "myfirst.cpp" #endif #endif // MYFIRST_HPP

B y defi ni ng or om i tti ng th e p rep roces s or s ym bol USE_EXPORT, we can now s elect between th e two m odels . I f a p rog ram defi nes USE_EXPORT before i t i nclu des myfirst.hpp, th e s ep arati on m odel i s u s ed:

// use separation model: #define USE_EXPORT #include "myfirst.hpp" …

I f a p rog ram does not defi ne USE_EXPORT , th e i nclu s i on m odel i s u s ed becau s e i n th i s cas e myfirst.hpp au tom ati cally i nclu des th e defi ni ti ons i n myfirst.cpp:

// use inclusion model: #include "myfirst.hpp" …

D es p i te th i s flex i bi li ty, we s h ou ld rei terate th at bes i des th e obv i ou s log i s ti cal di fferences , th ere can be s u btle s em anti c di fferences between th e two m odels .

N ote th at we can als o ex p li ci tly i ns tanti ate ex p orted tem p lates . I n th i s cas e th e tem p late defi ni ti on can be i n anoth er fi le. T o be able to ch oos e between th e i nclu s i on m odel, th e s ep arati on m odel, and ex p li ci t i ns tanti on, we can com bi ne th e org ani z ati on controlled by USE_EXPORT wi th th e conv enti ons des cri bed i n Secti on 6.2.2 on p ag e 67 .

Page 103: CPlusPlus Templates The Complete Guide
Page 104: CPlusPlus Templates The Complete Guide

6.4 Templates and inline

D eclari ng s h ort fu ncti ons to be i nli ne i s a com m on tool to i m p rov e th e ru nni ng ti m e of p rog ram s . T h e inline s p eci fi er i ndi cates to th e i m p lem entati on th at i nli ne s u bs ti tu ti on of th e fu ncti on body at th e p oi nt of call i s p referred ov er th e u s u al fu ncti on call m ech ani s m . H owev er, an i m p lem entati on i s not req u i red to p erform th i s i nli ne s u bs ti tu ti on at th e p oi nt of call.

B oth fu ncti on tem p lates and i nli ne fu ncti ons can be defi ned i n m u lti p le trans lati on u ni ts . T h i s i s u s u ally ach i ev ed by p laci ng th e defi ni ti on i n a h eader fi le th at i s i nclu ded by m u lti p le dot-C fi les .

T h i s m ay lead to th e i m p res s i on th at fu ncti on tem p lates are i nli ne by defau lt. H owev er, th ey' re not. I f you wri te fu ncti on tem p lates th at s h ou ld be h andled as i nli ne fu ncti ons , you s h ou ld u s e th e inline s p eci fi er (u nles s th e fu ncti on i s i nli ne already becau s e i t i s defi ned i ns i de a clas s defi ni ti on).

T h erefore, m any s h ort tem p late fu ncti ons th at are not p art of a clas s defi ni ti on s h ou ld be declared wi th inline. [3 ]

[3 ] W e m ay not always ap p ly th i s ru le of th u m b becau s e i t m ay di s tract from th e top i c at h and.

Page 105: CPlusPlus Templates The Complete Guide

6.5 Precompiled Headers

E v en wi th ou t tem p lates , C + + h eader fi les can becom e v ery larg e and th erefore tak e a long ti m e to com p i le. T em p lates add to th i s tendency, and th e ou tcry of wai ti ng p rog ram m ers h as i n m any cas es dri v en v endors to i m p lem ent a s ch em e u s u ally k nown as pr ec ompi led head er s. T h i s s ch em e op erates ou ts i de th e s cop e of th e s tandard and reli es on v endor-s p eci fi c op ti ons . A lth ou g h we leav e th e detai ls on h ow to create and u s e p recom p i led h eader fi les to th e docu m entati on of th e v ari ou s C + + com p i lati on s ys tem s th at h av e th i s featu re, i t i s u s efu l to g ai n s om e u nders tandi ng of h ow i t work s .

W h en a com p i ler trans lates a fi le, i t does s o s tarti ng from th e beg i nni ng of th e fi le and work s th rou g h to th e end. A s i t p roces s es each tok en from th e fi le (wh i ch m ay com e from #included fi les ), i t adap ts i ts i nternal s tate, i nclu di ng s u ch th i ng s as addi ng entri es to a table of s ym bols s o th ey m ay be look ed u p later. W h i le doi ng s o, th e com p i ler m ay als o g enerate code i n obj ect fi les .

T h e p recom p i led h eader s ch em e reli es on th e fact th at code can be org ani z ed i n s u ch a m anner th at m any fi les s tart wi th th e s am e li nes of code. L et' s as s u m e for th e s ak e of arg u m ent th at ev ery fi le to be com p i led s tarts wi th th e s am e N li nes of code. W e cou ld com p i le th es e N li nes and s av e th e com p lete s tate of th e com p i ler at th at p oi nt i n a s o-called pr ec ompi led head er . T h en, for ev ery fi le i n ou r p rog ram , we cou ld reload th e s av ed s tate and s tart com p i lati on at li ne N+1 . A t th i s p oi nt i t i s worth wh i le to note th at reloadi ng th e s av ed s tate i s an op erati on th at can be orders of m ag ni tu de fas ter th an actu ally com p i li ng th e fi rs t N li nes . H owev er, s av i ng th e s tate i n th e fi rs t p lace i s typ i cally m ore ex p ens i v e th an j u s t com p i li ng th e N li nes . T h e i ncreas e i n cos t v ari es rou g h ly from 20 to 200 p ercent.

T h e k ey to m ak i ng effecti v e u s e of p recom p i led h eaders i s to ens u re th at—as m u ch as p os s i ble— fi les s tart wi th a m ax i m u m nu m ber of com m on li nes of code. I n p racti ce th i s m eans th e fi les m u s t s tart wi th th e s am e #include di recti v es , wh i ch (as m enti oned earli er) cons u m e a s u bs tanti al p orti on of ou r bu i ld ti m e. H ence, i t can be v ery adv antag eou s to p ay attenti on to th e order i n wh i ch h eaders are i nclu ded. F or ex am p le, th e followi ng two fi les

#include <iostream> #include <vector> #include <list> …

and

Page 106: CPlusPlus Templates The Complete Guide

#include <list> #include <vector> …

i nh i bi t th e u s e of p recom p i led h eaders becau s e th ere i s no com m on i ni ti al s tate i n th e s ou rces .

Som e p rog ram m ers deci de th at i t i s better to #include s om e ex tra u nneces s ary h eaders th an to p as s on an op p ortu ni ty to accelerate th e trans lati on of a fi le u s i ng a p recom p i led h eader. T h i s deci s i on can cons i derably eas e th e m anag em ent of th e i nclu s i on p oli cy. F or ex am p le, i t i s u s u ally relati v ely s trai g h tforward to create a h eader fi le nam ed std.hpp th at i nclu des all th e s tandard h eaders [4 ]:

[4 ] I n th eory, th e s tandard h eaders do not actu ally need to corres p ond to p h ys i cal fi les . I n p racti ce, h owev er, th ey do, and th e fi les are v ery larg e.

#include <iostream> #include <string> #include <vector> #include <deque> #include <list> …

T h i s fi le can th en be p recom p i led, and ev ery p rog ram fi le th at m ak es u s e of th e s tandard li brary can th en s i m p ly be s tarted as follows :

#include "std.hpp" …

N orm ally th i s wou ld tak e a wh i le to com p i le, bu t g i v en a s ys tem wi th s u ffi ci ent m em ory, th e p recom p i led h eader s ch em e allows i t to be p roces s ed s i g ni fi cantly fas ter th an alm os t any s i ng le s tandard h eader wou ld req u i re wi th ou t p recom p i lati on. T h e s tandard h eaders are p arti cu larly conv eni ent i n th i s way becau s e th ey rarely ch ang e, and h ence th e p recom p i led h eader for ou r std.hpp fi le can be bu i lt once. [5 ] O th erwi s e, p recom p i led h eaders are typ i cally p art of th e dep endency confi g u rati on of a p roj ect (for ex am p le, th ey are u p dated as needed by th e p op u lar make tool).

[5 ] Som e com m i ttee m em bers fi nd th e concep t of a com p reh ens i v e std.hpp h eader s o conv eni ent th at th ey h av e s u g g es ted i ntrodu ci ng i t as a s tandard h eader. W e wou ld th en be able to wri te #include <std>. Som e ev en s u g g es t th at i t s h ou ld be i m p li ci tly i nclu ded s o th at all th e s tandard li brary faci li ti es becom e av ai lable wi th ou t #include.

O ne attracti v e ap p roach to m anag e p recom p i led h eaders i s to create lay er s of

Page 107: CPlusPlus Templates The Complete Guide

p recom p i led h eaders th at g o from th e m os t wi dely u s ed and s table h eaders (for ex am p le, ou r std.hpp h eader) to h eaders th at aren' t ex p ected to ch ang e all th e ti m e and th erefore are s ti ll worth p recom p i li ng . H owev er, i f h eaders are u nder h eav y dev elop m ent, creati ng p recom p i led h eaders for th em can tak e m ore ti m e th an wh at i s s av ed by reu s i ng th em . A k ey concep t to th i s ap p roach i s th at a p recom p i led h eader for a m ore s table layer can be reu s ed to i m p rov e th e p recom p i lati on ti m e of a les s s table h eader. F or ex am p le, s u p p os e th at i n addi ti on to ou r std.hpp h eader (wh i ch we h av e p recom p i led), we als o defi ne a core.hpp h eader th at i nclu des addi ti onal faci li ti es th at are s p eci fi c to ou r p roj ect bu t noneth eles s ach i ev e a certai n lev el of s tabi li ty:

#include "std.hpp" #include "core_data.hpp" #include "core_algos.hpp" …

B ecau s e th i s fi le s tarts wi th #include "std.hpp" , th e com p i ler can load th e as s oci ated p recom p i led h eader and conti nu e wi th th e nex t li ne wi th ou t recom p i li ng all th e s tandard h eaders . W h en th e fi le i s com p letely p roces s ed, a new p recom p i led h eader can be p rodu ced. A p p li cati ons can th en u s e #include "core.hpp" to p rov i de acces s q u i ck ly to larg e am ou nts of fu ncti onali ty becau s e th e com p i ler can load th e latter p recom p i led h eader.

Page 108: CPlusPlus Templates The Complete Guide

6.6 Debugging Templates

T em p lates rai s e two clas s es of ch alleng es wh en i t com es to debu g g i ng th em . O ne s et of ch alleng es i s defi ni tely a p roblem for wri ters of tem p lates : H ow can we ens u re th at th e tem p lates we wri te wi ll fu ncti on for an y tem p late arg u m ents th at s ati s fy th e condi ti ons we docu m ent? T h e oth er clas s of p roblem s i s alm os t ex actly th e op p os i te: H ow can a u s er of a tem p late fi nd ou t wh i ch of th e tem p late p aram eter req u i rem ents i t v i olated wh en th e tem p late does not beh av e as docu m ented?

B efore we di s cu s s th es e i s s u es i n dep th , i t i s u s efu l to contem p late th e k i nds of cons trai nts th at m ay be i m p os ed on tem p late p aram eters . I n th i s s ecti on we deal m os tly wi th th e cons trai nts th at lead to com p i lati on errors wh en v i olated, and we call th es e cons trai nts sy n tac ti c c on str ai n ts. Syntacti c cons trai nts can i nclu de th e need for a certai n k i nd of cons tru ctor to ex i s t, for a p arti cu lar fu ncti on call to be u nam bi g u ou s , and s o forth . T h e oth er k i nd of cons trai nt we call seman ti c c on str ai n ts. T h es e cons trai nts are m u ch h arder to v eri fy m ech ani cally. I n th e g eneral cas e, i t m ay not ev en be p racti cal to do s o. F or ex am p le, we m ay req u i re th at th ere be a < op erator defi ned on a tem p late typ e p aram eter (wh i ch i s a s yntacti c cons trai nt), bu t u s u ally we' ll als o req u i re th at th e op erator actu ally defi nes s om e s ort of orderi ng on i ts dom ai n (wh i ch i s a s em anti c cons trai nt).

T h e term c on c ept i s often u s ed to denote a s et of cons trai nts th at i s rep eatedly req u i red i n a tem p late li brary. F or ex am p le, th e C + + s tandard li brary reli es on s u ch concep ts as r an d om ac c ess i ter ator and d ef au lt c on str u c ti b le. C oncep ts can form h i erarch i es i n th e s ens e th at one concep t can be a refi nem ent of anoth er. T h e m ore refi ned concep t i nclu des all th e cons trai nts of th e oth er concep t bu t adds a few m ore. F or ex am p le, th e concep t r an d om ac c ess i ter ator refi nes th e concep t b i d i r ec ti on al i ter ator i n th e C + + s tandard li brary. W i th th i s term i nolog y i n p lace, we can s ay th at debu g g i ng tem p late code i nclu des a s i g ni fi cant am ou nt of determ i ni ng h ow concep ts are v i olated i n th e tem p late i m p lem entati on and i n th ei r u s e.

6.6.1 Decoding the Error Novel

O rdi nary com p i lati on errors are norm ally q u i te s u cci nct and to th e p oi nt. F or ex am p le, wh en a com p i ler s ays " class X has no member 'fun', " i t u s u ally i s n' t too h ard to fi g u re ou t wh at i s wrong i n ou r code (for ex am p le, we m i g h t h av e m i s typ ed run as fun). N ot s o wi th tem p lates . C ons i der th e followi ng relati v ely s i m p le code ex cerp t u s i ng th e C + + s tandard li brary. I t contai ns a fai rly s m all m i s tak e: list<string> i s u s ed, bu t we are s earch i ng u s i ng a greater<int> fu ncti on obj ect, wh i ch s h ou ld h av e been a greater<string> obj ect:

std::list<std::string> coll; … // Find the first element greater than "A" std::list<std::string>::iterator pos;

Page 109: CPlusPlus Templates The Complete Guide

pos = std::find_if(coll.begin(),coll.end(), // range std::bind2nd(std::greater<int>(),"A")); // criterion

T h i s s ort of m i s tak e com m only h ap p ens wh en cu tti ng and p as ti ng s om e code and forg etti ng to adap t p arts of i t.

A v ers i on of th e p op u lar G N U C + + com p i ler rep orts th e followi ng error:

/local/include/stl/_algo.h: In function 'struct _STL::_List_iterator<_STL::basic _string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Nonconst_tra its<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > > _STL::find_if<_STL::_List_iterator<_STL::basic_string<char,_STL::char_traits<cha r>,_STL::allocator<char> >,_STL::_Nonconst_traits<_STL::basic_string<char,_STL:: char_traits<char>,_STL::allocator<char> > > >, _STL::binder2nd<_STL::greater<int > > >(_STL::_List_iterator<_STL::basic_string<char,_STL::char_traits<char>,_STL: :allocator<char> >,_STL::_Nonconst_traits<_STL::basic_string<char,_STL::char_tra its<char>,_STL::allocator<char> > > >, _STL::_List_iterator<_STL::basic_string<c har,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_Nonconst_traits<_STL: :basic_string<char,_STL::char_traits<char>,_STL::allocator<char> > > >, _STL::bi nder2nd<_STL::greater<int> >, _STL::input_iterator_tag)': /local/include/stl/_algo.h:115: instantiated from '_STL::find_if<_STL::_List_i terator<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >, _STL::_Nonconst_traits<_STL::basic_string<char,_STL::char_traits<char>,_STL::all ocator<char> > > >, _STL::binder2nd<_STL::greater<int> > >(_STL::_List_iterator< _STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<char> >,_STL::_N onconst_traits<_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<c har> > > >, _STL::_List_iterator<_STL::basic_string<char,_STL::char_traits<char> ,_STL::allocator<char> >,_STL::_Nonconst_traits<_STL::basic_string<char,_STL::ch ar_traits<char>,_STL::allocator<char> > > >, _STL::binder2nd<_STL::greater<int> >)' testprog.cpp:18: instantiated from here /local/include/stl/_algo.h:78: no match for call to '(_STL::binder2nd<_STL::grea ter<int> >) (_STL::basic_string<char,_STL::char_traits<char>,_STL::allocator<cha r> > &)' /local/include/stl/_function.h:261: candidates are: bool _STL::binder2nd<_STL::g reater<int> >::operator ()(const int &) const

A m es s ag e li k e th i s s tarts look i ng m ore li k e a nov el th an a di ag nos ti c. I t can als o be ov erwh elm i ng to th e p oi nt of di s cou rag i ng nov i ce tem p late u s ers . H owev er, wi th s om e p racti ce, m es s ag es li k e th i s becom e m anag eable, and th e errors are relati v ely eas i ly located.

T h e fi rs t p art of th i s error m es s ag e s ays th at an error occu rred i n a fu ncti on tem p late i ns tance (wi th a h orri bly long nam e) deep i ns i de th e /local/include/stl/_algo.h h eader. N ex t, th e com p i ler rep orts wh y i t i ns tanti ated th at p arti cu lar i ns tance. I n th i s cas e i t all s tarted on li ne 18 of testprog.cpp (wh i ch i s th e fi le contai ni ng ou r ex am p le code), wh i ch cau s ed th e i ns tanti ati on of a find_if tem p late on li ne 115 of th e _algo.h h eader. T h e com p i ler rep orts all th i s i n cas e we s i m p ly were not ex p ecti ng all th es e tem p lates to be i ns tanti ated. I t allows u s to determ i ne th e ch ai n of ev ents th at cau s ed th e i ns tanti ati ons .

H owev er, i n ou r ex am p le we' re wi lli ng to beli ev e th at all k i nds of tem p lates needed to be i ns tanti ated, and we j u s t wonder wh y i t di dn' t work . T h i s i nform ati on com es i n th e las t p art of th e m es s ag e: T h e p art th at s ays " no match for call" i m p li es th at a fu ncti on call cou ld not

Page 110: CPlusPlus Templates The Complete Guide

be res olv ed becau s e th e typ es of th e arg u m ents and th e p aram eter typ es di dn' t m atch . F u rth erm ore, j u s t after th i s , th e li ne contai ni ng " candidates are" ex p lai ns th at th ere was a s i ng le candi date typ e ex p ecti ng an i nteg er typ e (p aram eter typ e const int&). L ook i ng back at li ne 18 of th e p rog ram , we s ee std::bind2nd(std::greater<int>(),"A"), wh i ch does i ndeed contai n an i nteg er typ e (<int>) th at i s not com p ati ble wi th th e s tri ng typ e obj ects for wh i ch we' re look i ng i n ou r ex am p le. R ep laci ng <int> wi th <std::string> m ak es th e p roblem g o away.

T h ere i s no dou bt th at th e error m es s ag e cou ld be better s tru ctu red. T h e actu al p roblem cou ld be om i tted before th e h i s tory of th e i ns tanti ati on, and i ns tead of u s i ng fu lly ex p anded tem p late i ns tanti ati on nam es li k e MyTemplate<YourTemplate<int> > , decom p os i ng th e i ns tance as i n MyTemplate<T> with T=YourTemplate<int> can redu ce th e ov erwh elm i ng leng th of nam es . H owev er, i t i s als o tru e th at all th e i nform ati on i n th i s di ag nos ti c cou ld be u s efu l i n s om e s i tu ati ons . I t i s th erefore not s u rp ri s i ng th at oth er com p i lers p rov i de s i m i lar i nform ati on (alth ou g h s om e u s e th e s tru ctu ri ng tech ni q u es m enti oned).

6.6.2 Shallow Instantiation

D i ag nos ti cs s u ch as th os e di s cu s s ed earli er ari s e wh en errors are fou nd after a long ch ai n of i ns tanti ati ons . T o i llu s trate th i s , cons i der th e followi ng s om ewh at contri v ed code:

template <typename T> void clear (T const& p) { *p=0; // assumes T is a pointer-like type } template <typename T> void core (T const& p) { clear(p); } template <typename T> void middle (typename T::Index p) { core(p); } template <typename T> void shell (T const& env) { typename T::Index i; middle<T>(i); } class Client { public: typedef int Index; }; Client main_client;

Page 111: CPlusPlus Templates The Complete Guide

int main() { shell(main_client); }

T h i s ex am p le i llu s trates th e typ i cal layeri ng of s oftware dev elop m ent: H i g h -lev el fu ncti on tem p lates li k e shell() rely on com p onents li k e middle(), wh i ch th em s elv es m ak e u s e of bas i c faci li ti es li k e core(). W h en we i ns tanti ate shell() , all th e layers below i t als o need to be i ns tanti ated. I n th i s ex am p le, a p roblem i s rev ealed i n th e deep es t layer: core() i s i ns tanti ated wi th typ e int (from th e u s e of Client::Index i n middle()) and attem p ts to dereference a v alu e of th at typ e, wh i ch i s an error. A g ood g eneri c di ag nos ti c i nclu des a trace of all th e layers th at led to th e p roblem s , bu t we obs erv e th at s o m u ch i nform ati on can ap p ear u nwi eldy.

A n ex cellent di s cu s s i on of th e core i deas s u rrou ndi ng th i s p roblem can be fou nd i n [ S tr ou str u pD n E ] , i n wh i ch B j arne Strou s tru p i denti fi es two clas s es of ap p roach es to determ i ne earli er wh eth er tem p late arg u m ents s ati s fy a s et of cons trai nts : th rou g h a lang u ag e ex tens i on or th rou g h earli er p aram eter u s e. W e cov er th e form er op ti on to s om e ex tent i n Secti on 13 .11 on p ag e 218 . T h e latter alternati v e cons i s ts of forci ng any errors i n shallow i n stan ti ati on s. T h i s i s ach i ev ed by i ns erti ng u nu s ed code wi th no oth er p u rp os e th an to tri g g er an error i f th at code i s i ns tanti ated wi th tem p late arg u m ents th at do not m eet th e req u i rem ents of deep er lev els of tem p lates .

I n ou r p rev i ou s ex am p le we cou ld add code i n shell() th at attem p ts to dereference a v alu e of typ e T::Index. F or ex am p le:

template <typename T> inline void ignore(T const&) { } template <typename T> void shell (T const& env) { class ShallowChecks { void deref(T::Index ptr) { ignore(*ptr); } }; typename T::Index i; middle(i); }

I f T i s a typ e s u ch th at T::Index cannot be dereferenced, an error i s now di ag nos ed on th e local clas s ShallowChecks. N ote th at becau s e th e local clas s i s not actu ally u s ed, th e added code does not i m p act th e ru nni ng ti m e of th e shell() fu ncti on. U nfortu nately, m any com p i lers wi ll warn abou t th e fact th at ShallowChecks i s not u s ed (and nei th er are i ts

Page 112: CPlusPlus Templates The Complete Guide

m em bers ). T ri ck s s u ch as th e u s e of th e ignore() tem p late can be u s ed to i nh i bi t s u ch warni ng s , bu t th ey add to th e com p lex i ty of th e code.

C learly, th e dev elop m ent of th e du m m y code i n ou r ex am p le can becom e as com p lex as th e code th at i m p lem ents th e actu al fu ncti onali ty of th e tem p late. T o control th i s com p lex i ty i t i s natu ral to attem p t to collect v ari ou s s ni p p ets of du m m y code i n s om e s ort of li brary. F or ex am p le, s u ch a li brary cou ld contai n m acros th at ex p and to code th at tri g g ers th e ap p rop ri ate error wh en a tem p late p aram eter s u bs ti tu ti on v i olates th e concep t u nderlyi ng th at p arti cu lar p aram eter. T h e m os t p op u lar s u ch li brary i s th e Con c ept Chec k L i b r ar y , wh i ch i s p art of th e B oos t di s tri bu ti on (s ee [B C C L ] ).

U nfortu nately, th e tech ni q u e i s n' t p arti cu larly p ortable (th e way errors are di ag nos ed di ffers cons i derably from one com p i ler to anoth er) and s om eti m es m as k s i s s u es th at cannot be cap tu red at a h i g h er lev el.

6.6.3 Long Symbols

T h e error m es s ag e analyz ed i n Secti on 6.6.1 on p ag e 7 5 dem ons trates anoth er p roblem of tem p lates : I ns tanti ated tem p late code can res u lt i n v ery long s ym bols . F or ex am p le, i n th e i m p lem entati on u s ed earli er std::string i s ex p anded to

_STL::basic_string<char,_STL::char_traits<char>, _STL::allocator<char> >

Som e p rog ram s th at u s e th e C + + s tandard li brary p rodu ce s ym bols th at contai n m ore th an 10, 000 ch aracters . T h es e v ery long s ym bols can als o cau s e errors or warni ng s i n com p i lers , li nk ers , and debu g g ers . M odern com p i lers u s e com p res s i on tech ni q u es to redu ce th i s p roblem , bu t i n error m es s ag es th i s i s not ap p arent.

6.6.4 Tracers

So far we h av e di s cu s s ed bu g s th at ari s e wh en com p i li ng or li nk i ng p rog ram s th at contai n tem p lates . H owev er, th e m os t ch alleng i ng tas k of ens u ri ng th at a p rog ram beh av es correctly at ru n ti m e often f ollow s a s u cces s fu l bu i ld. T em p lates can s om eti m es m ak e th i s tas k a li ttle m ore di ffi cu lt becau s e th e beh av i or of g eneri c code rep res ented by a tem p late dep ends u ni q u ely on th e cli ent of th at tem p late (certai nly m u ch m ore s o th an ordi nary clas s es and fu ncti ons ). A tracer i s a s oftware dev i ce th at can allev i ate th at as p ect of debu g g i ng by detecti ng p roblem s i n tem p late defi ni ti ons early i n th e dev elop m ent cycle.

A tracer i s a u s er-defi ned clas s th at can be u s ed as an arg u m ent for a tem p late to be tes ted. O ften, i t i s wri tten j u s t to m eet th e req u i rem ents of th e tem p late and no m ore th an th os e req u i rem ents . M ore i m p ortant, h owev er, a tracer s h ou ld g enerate a tr ac e of th e op erati ons th at are i nv ok ed on i t. T h i s allows , for ex am p le, to v eri fy ex p eri m entally th e effi ci ency of alg ori th m s as well as th e s eq u ence of op erati ons .

Page 113: CPlusPlus Templates The Complete Guide

H ere i s an ex am p le of a tracer th at m i g h t be u s ed to tes t a s orti ng alg ori th m :

// basics/tracer.hpp #include <iostream> class SortTracer { private: int value; // integer value to be sorted int generation; // generation of this tracer static long n_created; // number of constructor calls static long n_destroyed; // number of destructor calls static long n_assigned; // number of assignments static long n_compared; // number of comparisons static long n_max_live; // maximum of existing objects // recompute maximum of existing objects static void update_max_live() { if (n_created-n_destroyed > n_max_live) { n_max_live = n_created-n_destroyed; } } public: static long creations() { return n_created; } static long destructions() { return n_destroyed; } static long assignments() { return n_assigned; } static long comparisons() { return n_compared; } static long max_live() { return n_max_live; } public: // constructor SortTracer (intv=0):value(v), generation(1) { ++n_created; update_max_live(); std::cerr << "SortTracer #" << n_created << ", created generation " << generation << " (total: " << n_created - n_destroyed << ")\n"; } // copy constructor SortTracer (SortTracer const& b) : value(b.value), generation(b.generation+1) { ++n_created; update_max_live(); std::cerr << "SortTracer #" << n_created << ", copied as generation " << generation << " (total: " << n_created - n_destroyed

Page 114: CPlusPlus Templates The Complete Guide

<< ")\n"; } // destructor ~SortTracer() { ++n_destroyed; update_max_live(); std::cerr << "SortTracer generation " << generation << " destroyed (total: " << n_created - n_destroyed << ")\n"; } // assignment SortTracer& operator= (SortTracer const& b) { ++n_assigned; std::cerr << "SortTracer assignment #" << n_assigned << " (generation " << generation << " = " << b.generation << ")\n"; value = b.value; return *this; } // comparison friend bool operator < (SortTracer const& a, SortTracer const& b) { ++n_compared; std::cerr << "SortTracer comparison #" << n_compared << " (generation " << a.generation << " < " << b.generation << ")\n"; return a.value < b.value; } int val() const { return value; } };

I n addi ti on to th e v alu e to s ort, value , th e tracer p rov i des s ev eral m em bers to trace an actu al s ort: generation traces for each obj ect h ow m any cop i es i t i s from th e ori g i nal. T h e oth er s tati c m em bers trace th e nu m ber of creati ons (cons tru ctor calls ), des tru cti ons , as s i g nm ent com p ari s ons , and th e m ax i m u m nu m ber of obj ects th at ev er ex i s ted.

T h e s tati c m em bers are defi ned i n a s ep arate dot-C fi le:

// basics/tracer.cpp #include "tracer.hpp" long SortTracer::n_created = 0; long SortTracer::n_destroyed = 0; long SortTracer::n_max_live = 0; long SortTracer::n_assigned = 0; long SortTracer::n_compared = 0;

Page 115: CPlusPlus Templates The Complete Guide

T h i s p arti cu lar tracer allows u s to track th e p attern or enti ty creati on and des tru cti on as well as as s i g nm ents and com p ari s ons p erform ed by a g i v en tem p late. T h e followi ng tes t p rog ram i llu s trates th i s for th e std::sort alg ori th m of th e C + + s tandard li brary:

// basics/tracertest.cpp #include <iostream> #include <algorithm> #include "tracer.hpp" int main() { // prepare sample input: SortTracer input[]={7,3,5,6,4,2,0,1,9,8}; // print initial values: for (int i=0; i<10; ++i) { std::cerr << input[i].val() << ' '; } std::cerr << std::endl; // remember initial conditions: long created_at_start = SortTracer::creations(); long max_live_at_start = SortTracer::max_live(); long assigned_at_start = SortTracer::assignments(); long compared_at_start = SortTracer::comparisons(); // execute algorithm: std::cerr << "---[ Start std::sort() ]--------------------\n"; std::sort<>(&input[0], &input[9]+1); std::cerr << "---[ End std::sort() ]----------------------\n"; // verify result: for (int i=0; i<10; ++i) { std::cerr << input[i].val() << ' '; } std::cerr << "\n\n"; // final report: std::cerr << "std::sort() of 10 SortTracer's" << " was performed by:\n " << SortTracer::creations() - created_at_start << " temporary tracers\n " << "up to " << SortTracer::max_live() << " tracers at the same time (" << max_live_at_start << " before)\n " << SortTracer::assignments() - assigned_at_start << " assignments\n " << SortTracer::comparisons() - compared_at_start << " comparisons\n\n"; }

R u nni ng th i s p rog ram creates a cons i derable am ou nt of ou tp u t, bu t m u ch can be conclu ded from th e " fi nal rep ort." F or one i m p lem entati on of th e std::sort() fu ncti on, we fi nd th e

Page 116: CPlusPlus Templates The Complete Guide

followi ng :

std::sort() of 10 SortTracer's was performed by: 15 temporary tracers up to 12 tracers at the same time (10 before) 33 assignments 27 comparisons

F or ex am p le, we s ee th at alth ou g h 15 tem p orary tracers were created i n ou r p rog ram wh i le s orti ng , at m os t two addi ti onal tracers ex i s ted at any one ti m e.

O u r tracer th u s fu lfi lls two roles : I t p rov es th at th e s tandard sort() alg ori th m req u i res no m ore fu ncti onali ty th an ou r tracer (for ex am p le, op erators == and > were not needed), and i t g i v es u s a s ens e of th e cos t of th e alg ori th m . I t does not, h owev er, rev eal m u ch abou t th e correctnes s of th e s orti ng tem p late.

6.6.5 Oracles

T racers are relati v ely s i m p le and effecti v e, bu t th ey allow u s to trace th e ex ecu ti on of tem p lates only for s p eci fi c i np u t data and for a s p eci fi c beh av i or of i ts related fu ncti onali ty. W e m ay wonder, for ex am p le, wh at condi ti ons m u s t be m et by th e com p ari s on op erator for th e s orti ng alg ori th m to be m eani ng fu l (or correct), bu t i n ou r ex am p le we h av e only tes ted a com p ari s on op erator th at beh av es ex actly li k e les s -th an for i nteg ers .

A n ex tens i on of tracers i s k nown i n s om e ci rcles as or ac les (or r u n -ti me an aly si s or ac les). T h ey are tracers th at are connected to a s o-called i n f er en c e en g i n e—a p rog ram th at can rem em ber as s erti ons and reas ons abou t th em to i nfer certai n conclu s i ons . O ne s u ch s ys tem th at was ap p li ed to certai n p arts of a s tandard li brary i m p lem entati on i s called M E L AS and i s di s cu s s ed i n [ M u sser W an g D y n aV er i ] . [6 ]

[6 ] O ne au th or, D av i d M u s s er, was als o a k ey fi g u re i n th e dev elop m ent of th e C + + s tandard li brary. A m ong oth er th i ng s , h e des i g ned and i m p lem ented th e fi rs t as s oci ati v e contai ners .

O racles allow u s , i n s om e cas es , to v eri fy tem p late alg ori th m s dynam i cally wi th ou t fu lly s p eci fyi ng th e s u bs ti tu ti ng tem p late arg u m ents (th e oracles are th e arg u m ents ) or th e i np u t data (th e i nference eng i ne m ay req u es t s om e s ort of i np u t as s u m p ti on wh en i t g ets s tu ck ). H owev er, th e com p lex i ty of th e alg ori th m s th at can be analyz ed i n th i s way i s s ti ll m odes t (becau s e of th e li m i tati ons of th e i nference eng i nes ), and th e am ou nt of work i s cons i derable. F or th es e reas ons , we do not delv e i nto th e dev elop m ent of oracles , bu t th e i nteres ted reader s h ou ld ex am i ne th e p u bli cati on m enti oned earli er (and th e references contai ned th erei n).

6.6.6 Archetypes

W e m enti oned earli er th at tracers often p rov i de an i nterface th at i s th e m i ni m al req u i rem ent of th e tem p late th ey trace. W h en s u ch a m i ni m al tracer does not g enerate ru n-ti m e ou tp u t, i t

Page 117: CPlusPlus Templates The Complete Guide

i s s om eti m es called an ar c hety pe. A n arch etyp e allows u s to v eri fy th at a tem p late i m p lem entati on does not req u i re m ore s yntacti c cons trai nts th an i ntended. T yp i cally, a tem p late i m p lem enter wi ll want to dev elop an arch etyp e for ev ery concep t i denti fi ed i n th e tem p late li brary.

Page 118: CPlusPlus Templates The Complete Guide

6.7 Afternotes

T h e org ani z ati on of s ou rce code i n h eader fi les and dot-C fi les i s a p racti cal cons eq u ence of v ari ou s i ncarnati ons of th e s o-called on e-d ef i n i ti on r u le or O D R . A n ex tens i v e di s cu s s i on of th i s ru le i s p res ented i n A p p endi x A .

T h e i nclu s i on v ers u s s ep arati on m odel debate h as been a controv ers i al one. T h e i nclu s i on m odel i s a p rag m ati c ans wer di ctated larg ely by ex i s ti ng p racti ce i n C + + com p i ler i m p lem entati ons . H owev er, th e fi rs t C + + i m p lem entati on was di fferent: T h e i nclu s i on of tem p late defi ni ti ons was i m p li ci t, wh i ch created a certai n i llu s i on of separ ati on (s ee C h ap ter 10 for detai ls on th i s ori g i nal m odel).

[Strou s tru p D nE ] contai ns a g ood p res entati on of Strou s tru p ' s v i s i on for tem p late code org ani z ati on and th e as s oci ated i m p lem entati on ch alleng es . I t clearly was n' t th e i nclu s i on m odel. Y et, at s om e p oi nt i n th e s tandardi z ati on p roces s , i t s eem ed as i f th e i nclu s i on m odel was th e only v i able ap p roach after all. A fter s om e i ntens e debates , h owev er, th os e env i s i oni ng a m ore decou p led m odel g arnered s u ffi ci ent s u p p ort for wh at ev entu ally becam e th e s ep arati on m odel. U nli k e th e i nclu s i on m odel, th i s was a th eoreti cal m odel not bas ed on any ex i s ti ng i m p lem entati on. I t took m ore th an fi v e years to s ee i ts fi rs t i m p lem entati on p u bli s h ed (M ay 2002).

I t i s s om eti m es tem p ti ng to i m ag i ne ways of ex tendi ng th e concep t of p recom p i led h eaders s o th at m ore th an one h eader cou ld be loaded for a s i ng le com p i lati on. T h i s wou ld i n p ri nci p le allow for a fi ner g rai ned ap p roach to p recom p i lati on. T h e obs tacle h ere i s m ai nly th e p rep roces s or: M acros i n one h eader fi le can enti rely ch ang e th e m eani ng of s u bs eq u ent h eader fi les . H owev er, once a fi le h as been p recom p i led, m acro p roces s i ng i s com p leted, and i t i s h ardly p racti cal to attem p t to p atch a p recom p i led h eader for th e p rep roces s or effects i ndu ced by oth er h eaders .

A fai rly s ys tem ati c attem p t to i m p rov e C + + com p i ler di ag nos ti cs by addi ng du m m y code i n h i g h -lev el tem p lates can be fou nd i n J erem y Si ek ' s Con c ept Chec k L i b r ar y (s ee [B C C L ] ). I t i s p art of th e B oos t li brary (s ee [B oos t] ).

Page 119: CPlusPlus Templates The Complete Guide

6.8 Summary

• T em p lates ch alleng e th e clas s i c com p i ler-p lu s -li nk er m odel. T h erefore th ere are di fferent ap p roach es to org ani z e tem p late code: th e i nclu s i on m odel, ex p li ci t i ns tanti ati on, and th e s ep arati on m odel.

• U s u ally, you s h ou ld u s e th e i nclu s i on m odel (th at i s , p u t all tem p late code i n h eader fi les ).

• B y s ep arati ng tem p late code i nto di fferent h eader fi les for declarati ons and defi ni ti ons , you can m ore eas i ly s wi tch between th e i nclu s i on m odel and ex p li ci t i ns tanti ati on.

• T h e C + + s tandard defi nes a s ep arate com p i lati on m odel for tem p lates (u s i ng th e k eyword export). I t i s not yet wi dely av ai lable, h owev er.

• D ebu g g i ng code wi th tem p lates can be ch alleng i ng . • T em p late i ns tances m ay h av e v ery long nam es . • T o tak e adv antag e of p recom p i led h eaders , be s u re to k eep th e s am e

order for #include di recti v es .

Page 120: CPlusPlus Templates The Complete Guide

Chapter 7. Basic Template Terminology

So far we h av e i ntrodu ced th e bas i c concep t of tem p lates i n C + + . B efore we g o i nto detai ls , let' s look at th e term s of th e concep ts we u s e. T h i s i s neces s ary becau s e, i ns i de th e C + + com m u ni ty (and ev en i n th e s tandard), th ere i s a lack of p reci s i on reg ardi ng concep ts and term i nolog y.

Page 121: CPlusPlus Templates The Complete Guide

7.1 "Class Template" or "Template Class"?

I n C + + , s tru cts , clas s es , and u ni ons are collecti v ely called c lass ty pes. W i th ou t addi ti onal q u ali fi cati on, th e word " clas s " i n p lai n tex t typ e i s m eant to i nclu de clas s typ es i ntrodu ced wi th ei th er th e k eyword class or th e k eyword struct. [1] N ote s p eci fi cally th at " clas s typ e" i nclu des u ni ons , bu t " clas s " does not.

[1] I n C + + , th e only di fference between class and struct i s th at th e defau lt acces s for class i s private wh ereas th e defau lt acces s for struct i s public. H owev er, we p refer to u s e class for typ es th at u s e new C + + featu res , and we u s e struct for ordi nary C data s tru ctu re th at can be u s ed as " p lai n old data" (P O D ).

T h ere i s s om e confu s i on abou t h ow a clas s th at i s a tem p late i s called:

• T h e term c lass template s tates th at th e clas s i s a tem p late. T h at i s , i t i s a p aram eteri z ed des cri p ti on of a fam i ly of clas s es .

• T h e term template c lass on th e oth er h and h as been u s ed

- as a s ynonym for clas s tem p late.

- to refer to clas s es g enerated from tem p lates .

- to refer to clas s es wi th a nam e th at i s a tem p late-i d.

T h e di fference between th e s econd and th i rd m eani ng i s s om ewh at s u btle and u ni m p ortant for th e rem ai nder of th e tex t.

B ecau s e of th i s i m p reci s i on, we av oi d th e term template c lass i n th i s book .

Si m i larly, we u s e f u n c ti on template and memb er f u n c ti on template , bu t av oi d template f u n c ti on and template memb er f u n c ti on .

Page 122: CPlusPlus Templates The Complete Guide

7.2 Instantiation and Specialization

T h e p roces s of creati ng a reg u lar clas s , fu ncti on, or m em ber fu ncti on from a tem p late by s u bs ti tu ti ng actu al v alu es for i ts arg u m ents i s called template i n stan ti ati on . T h i s res u lti ng enti ty (clas s , fu ncti on, or m em ber fu ncti on) i s g eneri cally called a spec i ali z ati on .

H owev er, i n C + + th e i ns tanti ati on p roces s i s not th e only way to p rodu ce a s p eci ali z ati on. A lternati v e m ech ani s m s allow th e p rog ram m er to s p eci fy ex p li ci tly a declarati on th at i s ti ed to a s p eci al s u bs ti tu ti on of tem p late p aram eters . A s we i ntrodu ced i n Secti on 3 .3 on p ag e 27 , s u ch a s p eci ali z ati on i s i ntrodu ced by template<>:

template <typename T1, typename T2> // primary class template class MyClass { … }; template<> // explicit specialization class MyClass<std::string,float> { … };

Stri ctly s p eak i ng , th i s i s called a s o-called ex pli c i t spec i ali z ati on (as op p os ed to an i n stan ti ated or g en er ated spec i ali z ati on ).

A s i ntrodu ced i n Secti on 3 .4 on p ag e 29 , s p eci ali z ati ons th at s ti ll h av e tem p late p aram eters are called par ti al spec i ali z ati on s:

template <typename T> // partial specialization class MyClass<T,T> { … }; template <typename T> // partial specialization class MyClass<bool,T> { … };

W h en talk i ng abou t (ex p li ci t or p arti al) s p eci ali z ati ons , th e g eneral tem p late i s als o called th e pr i mar y template.

Page 123: CPlusPlus Templates The Complete Guide

7.3 Declarations versus Definitions

So far, th e words d ec lar ati on and d ef i n i ti on h av e been u s ed only a few ti m es i n th i s book . H owev er, th es e words carry wi th th em a rath er p reci s e m eani ng i n s tandard C + + , and th at i s th e m eani ng th at we u s e.

A d ec lar ati on i s a C + + cons tru ct th at i ntrodu ces or rei ntrodu ces a nam e i nto a C + + s cop e. T h i s i ntrodu cti on always i nclu des a p arti al clas s i fi cati on of th at nam e, bu t th e detai ls are not req u i red to m ak e a v ali d declarati on. F or ex am p le:

class C; // a declaration of C as a class void f(int p); // a declaration of f() as a function and p as a named parameter extern int v; // a declaration of v as a variable

N ote th at ev en th ou g h th ey h av e a " nam e, " m acro defi ni ti ons and goto labels are not cons i dered declarati ons i n C + + .

D eclarati ons becom e d ef i n i ti on s wh en th e detai ls of th ei r s tru ctu re are m ade k nown or, i n th e cas e of v ari ables , wh en s torag e s p ace m u s t be allocated. F or clas s typ e and fu ncti on defi ni ti ons , th i s m eans a brace-enclos ed body m u s t be p rov i ded. F or v ari ables , i ni ti ali z ati ons and a m i s s i ng extern lead to defi ni ti ons . H ere are ex am p les th at com p lem ent th e p recedi ng nondefi ni ti on declarati ons :

class C {}; // definition (and declaration) of class C void f(int p) { // definition (and declaration) of function f() std::cout << p << std::endl; } extern int v = 1; // an initializer makes this a definition for v int w; // global variable declarations not preceded by // extern are also definitions

B y ex tens i on, th e declarati on of a clas s tem p late or fu ncti on tem p late i s called a defi ni ti on i f i t h as a body. H ence,

template <typename T> void func (T);

i s a declarati on th at i s not a defi ni ti on, wh ereas

template <typename T>

Page 124: CPlusPlus Templates The Complete Guide

class S {};

i s i n fact a defi ni ti on.

Page 125: CPlusPlus Templates The Complete Guide

7.4 The One-Definition Rule

T h e C + + lang u ag e defi ni ti on p laces s om e cons trai nts on th e redeclarati on of v ari ou s enti ti es . T h e totali ty of th es e cons trai nts i s k nown as th e on e-d ef i n i ti on r u le or O D R . T h e detai ls of th i s ru le are q u i te com p lex and s p an a larg e v ari ety of s i tu ati ons . L ater ch ap ters i llu s trate th e v ari ou s res u lti ng facets i n each ap p li cable contex t, and you can fi nd a com p lete des cri p ti on of th e O D R i n A p p endi x A . F or now, i t s u ffi ces to rem em ber th e followi ng O D R bas i cs :

• N oni nli ne fu ncti ons and m em ber fu ncti ons , as well as g lobal v ari ables and s tati c data m em bers s h ou ld be defi ned only once acros s th e wh ole pr og r am.

• C las s typ es (i nclu di ng s tru cts and u ni ons ) and i nli ne fu ncti ons s h ou ld be defi ned at m os t once p er tr an slati on u n i t , and all th es e defi ni ti ons s h ou ld be i denti cal.

A tr an slati on u n i t i s wh at res u lts from p rep roces s i ng a s ou rce fi le; th at i s , i t i nclu des th e contents nam ed by #include di recti v es .

I n th e rem ai nder of th i s book , li n k ab le en ti ty m eans one of th e followi ng : a noni nli ne fu ncti on or m em ber fu ncti on, a g lobal v ari able or a s tati c data m em ber, i nclu di ng any s u ch th i ng s g enerated from a tem p late.

Page 126: CPlusPlus Templates The Complete Guide

7.5 Template Arguments versus Template Parameters

C om p are th e followi ng clas s tem p late

template <typename T, int N> class ArrayInClass { public: T array[N]; };

wi th a s i m i lar p lai n clas s :

class DoubleArrayInClass { public: double array[10]; };

T h e latter becom es es s enti ally eq u i v alent to th e form er i f we rep lace th e p aram eters T and N by double and 10 res p ecti v ely. I n C + + , th e nam e of th i s rep lacem ent i s denoted as

ArrayInClass<double,10>

N ote h ow th e nam e of th e tem p late i s followed by s o-called template ar g u men ts i n ang le brack ets .

R eg ardles s of wh eth er th es e arg u m ents are th em s elv es dep endent on tem p late p aram eters , th e com bi nati on of th e tem p late nam e, followed by th e arg u m ents i n ang le brack ets , i s called a template-i d .

T h i s nam e can be u s ed m u ch li k e a corres p ondi ng nontem p late enti ty wou ld be u s ed. F or ex am p le:

int main() { ArrayInClass<double,10> ad; ad.array[0] = 1.0; }

I t i s es s enti al to di s ti ng u i s h between template par ameter s and template ar g u men ts. I n s h ort, you can s ay th at you " p as s ar g u men ts to becom e par ameter s." [2 ] O r m ore p reci cely:

[2 ] I n th e academ i c world, ar g u men ts are s om eti m es called ac tu al

Page 127: CPlusPlus Templates The Complete Guide

par ameter s wh ereas par ameter s are called f or mal par ameter s.

• Template par ameter s are th os e nam es th at are li s ted after th e k eyword template i n th e tem p late declarati on or defi ni ti on (T and N i n ou r ex am p le).

• Template ar g u men ts are th e i tem s th at are s u bs ti tu ted for tem p late p aram eters (double and 10 i n ou r ex am p le). U nli k e tem p late p aram eters , tem p late arg u m ents can be m ore th an j u s t " nam es ."

T h e s u bs ti tu ti on of tem p late p aram eters by tem p late arg u m ents i s ex p li ci t wh en i ndi cated wi th a tem p late-i d, bu t th ere are v ari ou s s i tu ati ons wh en th e s u bs ti tu ti on i s i m p li ci t (for ex am p le, i f tem p late p aram eters are s u bs ti tu ted by th ei r defau lt arg u m ents ).

A fu ndam ental p ri nci p le i s th at any tem p late arg u m ent m u s t be a q u anti ty or v alu e th at can be determ i ned at com p i le ti m e. A s becom es clear later, th i s req u i rem ent trans lates i nto dram ati c benefi ts for th e ru n-ti m e cos ts of tem p late enti ti es . B ecau s e tem p late p aram eters are ev entu ally s u bs ti tu ted by com p i le-ti m e v alu es , th ey can th em s elv es be u s ed to form com p i le-ti m e ex p res s i ons . T h i s was ex p loi ted i n th e ArrayInClass tem p late to s i z e th e m em ber array array. T h e s i z e of an array m u s t be a s o-called c on stan t-ex pr essi on , and th e tem p late p aram eter N q u ali fi es as s u ch .

W e can p u s h th i s reas oni ng a li ttle fu rth er: B ecau s e tem p late p aram eters are com p i le-ti m e enti ti es , th ey can als o be u s ed to create v ali d tem p late arg u m ents . H ere i s an ex am p le:

template <typename T> class Dozen { public: ArrayInClass<T,12> contents; };

N ote h ow i n th i s ex am p le th e nam e T i s both a tem p late p aram eter and a tem p late arg u m ent. T h u s , a m ech ani s m i s av ai lable to enable th e cons tru cti on of m ore com p lex tem p lates from s i m p ler ones . O f cou rs e, th i s i s not fu ndam entally di fferent from th e m ech ani s m s th at allow u s to as s em ble typ es and fu ncti ons .

Page 128: CPlusPlus Templates The Complete Guide

Part II: Templates in Depth

T h e fi rs t p art of th i s book p rov i ded a tu tori al for m os t of th e lang u ag e concep ts u nderlyi ng C + + tem p lates . T h at p res entati on i s s u ffi ci ent to ans wer th e m aj ori ty of q u es ti ons th at m ay ari s e i n ev eryday C + + p rog ram m i ng . T h e s econd p art of th i s book p rov i des a reference th at ans wers ev en th e m ore u nu s u al q u es ti ons th at ari s e wh en p u s h i ng th e env elop e of th e lang u ag e to ach i ev e s om e adv anced s oftware effect. I f des i red, you can s k i p th i s p art on a fi rs t read and retu rn to s p eci fi c top i cs as p rom p ted by references i n later ch ap ters or after look i ng u p a concep t i n th e i ndex .

O u r g oal i s to be clear and com p lete, bu t als o to k eep th e di s cu s s i on conci s e. T o th i s end, ou r ex am p les are s h ort and often s om ewh at arti fi ci al. T h i s als o ens u res th at we don' t s tray from th e top i c at h and to u nrelated i s s u es .

I n addi ti on, we look at p os s i ble fu tu re ch ang es and ex tens i ons for th e tem p lates lang u ag e featu re i n C + + . T op i cs i nclu de:

• F u ndam ental tem p late declarati on i s s u es • T h e m eani ng of nam es i n tem p lates • T h e C + + tem p late i ns tanti ati on m ech ani s m s • T h e tem p late arg u m ent dedu cti on ru les • Sp eci ali z ati on and ov erloadi ng • F u tu re p os s i bi li ti es

Page 129: CPlusPlus Templates The Complete Guide

Chapter 8. Fundamentals in Depth

I n th i s ch ap ter we rev i ew s om e of th e fu ndam entals i ntrodu ced i n th e fi rs t p art of th i s book i n d epth: th e declarati on of tem p lates , th e res tri cti ons on tem p late p aram eters , th e cons trai nts on tem p late arg u m ents , and s o forth .

Page 130: CPlusPlus Templates The Complete Guide

8.1 Parameterized Declarations

C + + cu rrently s u p p orts two fu ndam ental k i nds of tem p lates : clas s tem p lates and fu ncti on tem p lates (s ee Secti on 13 .6 on p ag e 212 for a p os s i ble fu tu re ch ang e i n th i s area). T h i s clas s i fi cati on i nclu des m em ber tem p lates . Su ch tem p lates are declared m u ch li k e ordi nary clas s es and fu ncti ons , ex cep t for bei ng i ntrodu ced by a par ameter i z ati on c lau se of th e form

template<… parameters here… >

or p erh ap s

export template<… parameters here… >

(s ee Secti on 6.3 on p ag e 68 and Secti on 10.3 .3 on p ag e 14 9 for a detai led ex p lanati on of th e k eyword export).

W e' ll com e back to th e actu al tem p late p aram eter declarati ons i n a later s ecti on. A n ex am p le i llu s trates th e two k i nds of tem p lates , both as clas s m em bers and as ordi nary nam es p ace s cop e declarati ons :

template <typename T> class List { // a namespace scope class template public: template <typename T2> // a member function template List (List<T2> const&); // (constructor) … }; template <typename T> template <typename T2> List<T>::List (List<T2> const& b) // an out-of-class member function { // template definition … } template <typename T> int length (List<T> const&); // a namespace scope function template class Collection { template <typename T> // an in-class member class template class Node { // definition … }; template <typename T> // another member class template, class Handle; // without its definition

Page 131: CPlusPlus Templates The Complete Guide

template <typename T> // an in-class (and therefore implicitly T* alloc() { // inline) member function template … // definition } … }; template <typename T> // an out-of-class member class class Collection::Node { // template definition … };

N ote h ow m em ber tem p lates defi ned ou ts i de th ei r enclos i ng clas s can h av e m u lti p le template<…> p aram eteri z ati on clau s es : one for th e tem p late i ts elf and one for ev ery enclos i ng clas s tem p late. T h e clau s es are li s ted s tarti ng from th e ou term os t clas s tem p late.

U n i on templates are p os s i ble too (and th ey are cons i dered a k i nd of clas s tem p late):

template <typename T> union AllocChunk { T object; unsigned char bytes[sizeof(T)]; };

F u ncti on tem p lates can h av e defau lt call arg u m ents j u s t li k e ordi nary fu ncti on declarati ons :

template <typename T> void report_top (Stack<T> const&, int number = 10); template <typename T> void fill (Array<T>*, T const& = T()); // T() is zero for built-in types

T h e latter declarati on s h ows th at a defau lt call arg u m ent cou ld dep end on a tem p late p aram eter. W h en th e fill() fu ncti on i s called, th e defau lt arg u m ent i s not i ns tanti ated i f a s econd fu ncti on call arg u m ent i s s u p p li ed. T h i s ens u res th at no error i s i s s u ed i f th e defau lt call arg u m ent cannot be i ns tanti ated for a p arti cu lar T. F or ex am p le:

class Value { public: Value(int); // no default constructor }; void init (Array<Value>* array) {

Page 132: CPlusPlus Templates The Complete Guide

Value zero(0); fill(array, zero); // OK: = T() is not used fill(array); // ERROR: = T() is used, but not valid for T = Value }

I n addi ti on to th e two fu ndam ental k i nds of tem p lates , th ree oth er k i nds of declarati ons can be p aram eteri z ed u s i ng a s i m i lar notati on. A ll th ree corres p ond to defi ni ti ons of m em bers of clas s tem p lates [1]:

[1] T h ey are m u ch li k e ordi nary clas s m em bers , bu t th ey are occas i onally (erroneou s ly) referred to as memb er templates.

1. D e f i n i t i o n s o f m e m b e r f u n c t i o n s o f c l a s s t e m p l a t e s 2 . D e f i n i t i o n s o f n e s t e d c l a s s m e m b e r s o f c l a s s t e m p l a t e s 3 . D e f i n i t i o n s o f s t a t i c d a t a m e m b e r s o f c l a s s t e m p l a t e s

A lth ou g h th ey can be p aram eteri z ed, s u ch defi ni ti ons aren' t q u i te fi rs t-clas s tem p lates . T h ei r p aram eters are enti rely determ i ned by th e tem p late of wh i ch th ey are m em bers . H ere i s an ex am p le of s u ch defi ni ti ons :

template <int I> class CupBoard { void open(); class Shelf; static double total_weight; … }; template <int I> void CupBoard<I>::open() { … } template <int I> class CupBoard<I>::Shelf { … }; template <int I> double CupBoard<I>::total_weight = 0.0;

A lth ou g h s u ch p aram eteri z ed defi ni ti ons are com m only called templates , th ere are contex ts wh en th e term does n' t q u i te ap p ly to th em .

8.1.1 Virtual Member Functions

M em ber fu ncti on tem p lates cannot be declared v i rtu al. T h i s cons trai nt i s i m p os ed becau s e th e u s u al i m p lem entati on of th e v i rtu al fu ncti on call m ech ani s m u s es a fi x ed-s i z e table wi th one entry p er v i rtu al fu ncti on. H owev er, th e nu m ber of i ns tanti ati ons of a m em ber fu ncti on tem p late i s not fi x ed u nti l th e enti re p rog ram

Page 133: CPlusPlus Templates The Complete Guide

h as been trans lated. H ence, s u p p orti ng v i rtu al m em ber fu ncti on tem p lates wou ld req u i re s u p p ort for a wh ole new k i nd of m ech ani s m i n C + + com p i lers and li nk ers .

I n contras t, th e ordi nary m em bers of clas s tem p lates can be v i rtu al becau s e th ei r nu m ber i s fi x ed wh en a clas s i s i ns tanti ated:

template <typename T> class Dynamic { public: virtual ~Dynamic(); // OK: one destructor per instance of Dynamic<T> template <typename T2> virtual void copy (T2 const&); // ERROR: unknown number of instances of copy() // given an instance of Dynamic<T> };

8.1.2 Linkage of Templates

E v ery tem p late m u s t h av e a nam e and th at nam e m u s t be u ni q u e wi th i n i ts s cop e, ex cep t th at fu ncti on tem p lates can be ov erloaded (s ee C h ap ter 12). N ote es p eci ally th at, u nli k e clas s typ es , clas s tem p lates cannot s h are a nam e wi th a di fferent k i nd of enti ty:

int C; class C; // OK: class names and nonclass names are in a different ''space'' int X; template <typename T> class X; // ERROR: conflict with variable X struct S; template <typename T> class S; // ERROR: conflict with struct S

T em p late nam es h av e li nk ag e, bu t th ey cannot h av e C li n k ag e. N ons tandard li nk ag es m ay h av e an i m p lem entati on-dep endent m eani ng (h owev er, we don' t k now of an i m p lem entati on th at s u p p orts nons tandard nam e li nk ag es for tem p lates ):

extern "C++" template <typename T> void normal(); // this is the default: the linkage specification could be left out extern "C" template <typename T>

Page 134: CPlusPlus Templates The Complete Guide

void invalid(); // invalid: templates cannot have C linkage extern "Xroma" template <typename T> void xroma_link(); // nonstandard, but maybe some compiler will some day // support linkage compatible with the Xroma language

T em p lates u s u ally h av e ex ternal li nk ag e. T h e only ex cep ti ons are nam es p ace s cop e fu ncti on tem p lates wi th th e static s p eci fi er:

template <typename T> void external(); // refers to the same entity as a declaration of // the same name (and scope) in another file template <typename T> static void internal(); // unrelated to a template with the same name in // another file

N ote th at tem p lates cannot be declared i n a fu ncti on.

8.1.3 Primary Templates

N orm al declarati ons of tem p lates declare s o-called pr i mar y templates. Su ch tem p late declarati ons are declared wi th ou t addi ng tem p late arg u m ents i n ang le brack ets after th e tem p late nam e:

template<typename T> class Box; // OK: primary template template<typename T> class Box<T>; // ERROR template<typename T> void translate(T*); // OK: primary template template<typename T> void translate<T>(T*); // ERROR

N onp ri m ary clas s tem p lates occu r wh en declari ng s o-called par ti al spec i ali z ati on s wh i ch are di s cu s s ed i n C h ap ter 12. F u ncti on tem p lates m u s t always be p ri m ary tem p lates (bu t s ee Secti on 13 .7 on p ag e 213 for a p otenti al fu tu re lang u ag e ch ang e).

Page 135: CPlusPlus Templates The Complete Guide

8.2 Template Parameters

T h ere are th ree k i nds of tem p late p aram eters :

1. Ty p e p a r a m e t e r s ( t h e s e a r e b y f a r t h e m o s t c o m m o n ) 2 . N o n t y p e p a r a m e t e r s 3 . Te m p l a t e t e m p l a t e p a r a m e t e r s

T em p late p aram eters are declared i n th e i ntrodu ctory p aram eteri z ati on clau s e of a tem p late declarati on. Su ch declarati ons do not neces s ari ly need to be nam ed:

template <typename, int> class X;

A p aram eter nam e i s , of cou rs e, req u i red i f th e p aram eter i s referred to later i n th e tem p late. N ote als o th at a tem p late p aram eter nam e can be referred to i n a s u bs eq u ent p aram eter declarati on (bu t not before):

template <typename T, // the first parameter is used in the T* Root, // declaration of the second one and template<T*> class Buf> // the third one class Structure;

8.2.1 Type Parameters

T yp e p aram eters are i ntrodu ced wi th ei th er th e k eyword typename or th e k eyword class: T h e two are enti rely eq u i v alent. [2 ] T h e k eyword m u s t be followed by a s i m p le i denti fi er and th at i denti fi er m u s t be followed by a com m a to denote th e s tart of th e nex t p aram eter declarati on, a clos i ng ang le brack et (>) to denote th e end of th e p aram eteri z ati on clau s e, or an eq u al s i g n (=) to denote th e beg i nni ng of a defau lt tem p late arg u m ent.

[2 ] T h e k eyword class does n ot i m p ly th at th e s u bs ti tu ti ng arg u m ent s h ou ld be a clas s typ e. I t cou ld be alm os t any acces s i ble typ e. H owev er, clas s typ es th at are defi ned i n a fu ncti on (loc al c lasses) cannot be u s ed as tem p late arg u m ents (i ndep endent of wh eth er th e p aram eter was declared wi th typename or class).

W i th i n a tem p late declarati on, a typ e p aram eter acts m u ch li k e a ty ped ef n ame. F or ex am p le, i t i s not p os s i ble to u s e an elaborated nam e of th e form class T wh en T i s a tem p late p aram eter, ev en i f T were to be s u bs ti tu ted by a clas s typ e:

Page 136: CPlusPlus Templates The Complete Guide

template <typename Allocator> class List { class Allocator* allocator; // ERROR friend class Allocator; // ERROR … };

I t i s p os s i ble th at a m ech ani s m to enable s u ch a fri end declarati on wi ll be added i n th e fu tu re.

8.2.2 Nontype Parameters

N ontyp e tem p late p aram eters s tand for cons tant v alu es th at can be determ i ned at com p i le or li nk ti m e. [3 ] T h e typ e of s u ch a p aram eter (i n oth er words , th e typ e of th e v alu e for wh i ch i t s tands ) m u s t be one of th e followi ng :

[3 ] T em p late tem p late p aram eters do not denote typ es ei th er; h owev er, th ey are not cons i dered wh en talk i ng abou t n on ty pe p aram eters .

• A n i nteg er typ e or an enu m erati on typ e • A p oi nter typ e (i nclu di ng reg u lar obj ect p oi nter typ es , fu ncti on p oi nter

typ es , and p oi nter-to-m em ber typ es ) • A reference typ e (both references to obj ects and references to fu ncti ons

are accep table)

A ll oth er typ es are cu rrently ex clu ded (alth ou g h floati ng -p oi nt typ es m ay be added i n th e fu tu re, s ee Secti on 13 .4 on p ag e 210).

P erh ap s s u rp ri s i ng ly, th e declarati on of a nontyp e tem p late p aram eter can i n s om e cas es als o s tart wi th th e k eyword typename:

template<typename T, // a type parameter typename T::Allocator* Allocator> // a nontype parameter class List;

T h e two cas es are eas i ly di s ti ng u i s h ed becau s e th e fi rs t i s followed by a s i m p le i denti fi er, wh ereas th e s econd i s followed by a q u ali f i ed n ame (i n oth er words , a nam e contai ni ng a dou ble colon, ::). Secti on 1.1 on p ag e 4 3 and Secti on 9 .3 .2 on p ag e 13 0 ex p lai n th e need for th e k eyword typename i n th e nontyp e p aram eter.

F u ncti on and array typ es can be s p eci fi ed, bu t th ey are i m p li ci tly adj u s ted to th e p oi nter typ e to wh i ch th ey decay:

template<int buf[5]> class Lexer; // buf is really an int* template<int* buf> class Lexer; // OK: this is a redeclaration

Page 137: CPlusPlus Templates The Complete Guide

N ontyp e tem p late p aram eters are declared m u ch li k e v ari ables , bu t th ey cannot h av e nontyp e s p eci fi ers li k e static, mutable, and s o forth . T h ey can h av e const and volatile q u ali fi ers , bu t i f s u ch a q u ali fi er ap p ears at th e ou term os t lev el of th e p aram eter typ e, i t i s s i m p ly i g nored:

template<int const length> class Buffer; // const is useless here template<int length> class Buffer; // same as previous declaration

F i nally, nontyp e p aram eters are always r v alu es: T h ei r addres s cannot be tak en, and th ey cannot be as s i g ned to.

8.2.3 Template Template Parameters

T em p late tem p late p aram eters are p laceh olders for clas s tem p lates . T h ey are declared m u ch li k e clas s tem p lates , bu t th e k eywords struct and union cannot be u s ed:

template <template<typename X> class C> // OK void f(C<int>* p); template <template<typename X> struct C> // ERROR: struct not valid here void f(C<int>* p); template <template<typename X> union C> // ERROR: union not valid here void f(C<int>* p);

I n th e s cop e of th ei r declarati on, tem p late tem p late p aram eters are u s ed j u s t li k e oth er clas s tem p lates .

T h e p aram eters of tem p late tem p late p aram eters can h av e defau lt tem p late arg u m ents . T h es e defau lt arg u m ents ap p ly wh en th e corres p ondi ng p aram eters are not s p eci fi ed i n u s es of th e tem p late tem p late p aram eter:

template <template<typename T, typename A = MyAllocator> class Container> class Adaptation { Container<int> storage; // implicitly equivalent to // Container<T, MyAllocator> … };

T h e nam e of a tem p late p aram eter of a tem p late tem p late p aram eter can be u s ed only i n th e declarati on of oth er p aram eters of th at tem p late tem p late p aram eter.

Page 138: CPlusPlus Templates The Complete Guide

T h e followi ng contri v ed tem p late i llu s trates th i s concep t:

template <template<typename T, T*> class Buf> class Lexer { static char storage[5]; Buf<char, &Lexer<Buf>::storage> buf; … }; template <template<typename T> class List> class Node { static T* storage; // ERROR: a parameter of a template template // parameter cannot be used here … };

U s u ally h owev er, th e nam es of th e tem p late p aram eters of a tem p late tem p late p aram eter are not u s ed. A s a res u lt, th e form er p aram eters are often left u nnam ed altog eth er. F or ex am p le, ou r earli er Adaptation tem p late cou ld be declared as follows :

template <template <typename, typename = MyAllocator> class Container> class Adaptation { Container<int> storage; // implicitly equivalent to // Container<int, MyAllocator> … };

8.2.4 Default Template Arguments

C u rrently, only clas s tem p late declarati ons can h av e defau lt tem p late arg u m ents (s ee Secti on 13 .3 on p ag e 207 for li k ely ch ang es i n th i s area). A ny k i nd of tem p late p aram eter can be eq u i p p ed wi th a defau lt arg u m ent, alth ou g h i t m u s t m atch th e corres p ondi ng p aram eter. C learly, a defau lt arg u m ent s h ou ld not dep end on i ts own p aram eter. H owev er, i t m ay dep end on p rev i ou s p aram eters :

template <typename T, typename Allocator = allocator<T> > class List;

Si m i lar to defau lt fu ncti on call arg u m ents , a tem p late p aram eter can h av e a defau lt tem p late arg u m ent only i f defau lt arg u m ents were als o s u p p li ed for th e s u bs eq u ent p aram eters . T h e s u bs eq u ent defau lt v alu es are u s u ally p rov i ded i n th e s am e tem p late declarati on, bu t th ey cou ld als o h av e been declared i n a p rev i ou s declarati on of th at tem p late. T h e followi ng ex am p le m ak es th i s clear:

template <typename T1, typename T2, typename T3, typename T4 = char, typename T5 = char>

Page 139: CPlusPlus Templates The Complete Guide

class Quintuple; // OK template <typename T1, typename T2, typename T3 = char, typename T4, typename T5> class Quintuple; // OK: T4 and T5 already have defaults template <typename T1 = char, typename T2, typename T3, typename T4, typename T5> class Quintuple; // ERROR: T1 cannot have a default argument // because T2 doesn't have a default

D efau lt tem p late arg u m ents cannot be rep eated:

template<typename T = void> class Value; template<typename T = void> class Value; // ERROR: repeated default argument

Page 140: CPlusPlus Templates The Complete Guide

8.3 Template Arguments

T em p late arg u m ents are th e " v alu es " th at are s u bs ti tu ted for tem p late p aram eters wh en i ns tanti ati ng a tem p late. T h es e v alu es can be determ i ned u s i ng s ev eral di fferent m ech ani s m s :

• E x p li ci t tem p late arg u m ents : A tem p late nam e can be followed by ex p li ci t tem p late arg u m ent v alu es enclos ed i n ang le brack ets . T h e res u lti ng nam e i s called a template-i d .

• I nj ected clas s nam e: W i th i n th e s cop e of a clas s tem p late X wi th tem p late p aram eters P1 , P2, … , th e nam e of th at tem p late (X) can be eq u i v alent to th e tem p late-i d X<P1, P2, …>. See Secti on 9 .2.3 on p ag e 126 for detai ls .

• D efau lt tem p late arg u m ents : E x p li ci t tem p late arg u m ents can be om i tted from clas s tem p late i ns tances i f defau lt tem p late arg u m ents are av ai lable. H owev er, ev en i f all tem p late p aram eters h av e a defau lt v alu e, th e (p os s i bly em p ty) ang le brack ets m u s t be p rov i ded.

• A rg u m ent dedu cti on: F u ncti on tem p late arg u m ents th at are not ex p li ci tly s p eci fi ed m ay be dedu ced from th e typ es of th e fu ncti on call arg u m ents i n a call. T h i s i s des cri bed i n detai l i n C h ap ter 11. D edu cti on i s als o done i n a few oth er s i tu ati ons . I f all th e tem p late arg u m ents can be dedu ced, no ang le brack ets need to be s p eci fi ed after th e nam e of th e fu ncti on tem p late.

8.3.1 Function Template Arguments

T em p late arg u m ents for a fu ncti on tem p late can be s p eci fi ed ex p li ci tly or dedu ced from th e way th e tem p late i s u s ed. F or ex am p le:

// details/max.cpp template <typename T> inline T const& max (T const& a, T const& b) { return a<b?b:a; } int main() { max<double>(1.0, -3.0); // explicitly specify template argument max(1.0, -3.0); // template argument is implicitly deduced // to be double max<int>(1.0, 3.0); // the explicit <int> inhibits the deduction; // hence the result has type int

Page 141: CPlusPlus Templates The Complete Guide

}

Som e tem p late arg u m ents can nev er be dedu ced (s ee C h ap ter 11). T h e corres p ondi ng p aram eters are bes t p laced at th e beg i nni ng of th e li s t of tem p late p aram eters s o th ey can be s p eci fi ed ex p li ci tly wh i le allowi ng th e oth er arg u m ents to be dedu ced. F or ex am p le:

// details/implicit.cpp template <typename DstT, typename SrcT> inline DstT implicit_cast (SrcT const& x) // SrcT can be deduced, { // but DstT cannot return x; } int main() { double value = implicit_cast<double>(-1); }

I f we h ad rev ers ed th e order of th e tem p late p aram eters i n th i s ex am p le (i n oth er words , i f we h ad wri tten template<typename SrcT, typename DstT>), a call of implicit_cast wou ld h av e to s p eci fy both tem p late arg u m ents ex p li ci tly.

B ecau s e fu ncti on tem p lates can be ov erloaded, ex p li ci tly p rov i di ng all th e arg u m ents for a fu ncti on tem p late m ay not be s u ffi ci ent to i denti fy a s i ng le fu ncti on: I n s om e cas es , i t i denti fi es a set of fu ncti ons . T h e followi ng ex am p le i llu s trates a cons eq u ence of th i s obs erv ati on:

template <typename Func, typename T> void apply (Func func_ptr, T x) { func_ptr(x); } template <typename T> void single(T); template <typename T> void multi(T); template <typename T> void multi(T*); int main() { apply(&single<int>, 3); // OK apply(&multi<int>, 7); // ERROR: no single multi<int> }

I n th i s ex am p le, th e fi rs t call to apply() work s becau s e th e typ e of th e ex p res s i on &single<int> i s u nam bi g u ou s . A s a res u lt, th e tem p late arg u m ent v alu e for th e Func p aram eter i s eas i ly dedu ced. I n th e s econd call, h owev er, &multi<int> cou ld be one of two di fferent typ es and th erefore Func cannot be

Page 142: CPlusPlus Templates The Complete Guide

dedu ced i n th i s cas e.

F u rth erm ore, i t i s p os s i ble th at ex p li ci tly s p eci fyi ng th e tem p late arg u m ents for a fu ncti on tem p late res u lts i n an attem p t to cons tru ct an i nv ali d C + + typ e. C ons i der th e followi ng ov erloaded fu ncti on tem p late (RT1 and RT2 are u ns p eci fi ed typ es ):

template<typename T> RT1 test(typename T::X const*); template<typename T> RT2 test(...);

T h e ex p res s i on test<int> m ak es no s ens e for th e fi rs t of th e two fu ncti on tem p lates becau s e typ e int h as no m em ber typ e X. H owev er, th e s econd tem p late h as no s u ch p roblem . T h erefore, th e ex p res s i on &test<int> i denti fi es th e addres s of a s i ng le fu ncti on. T h e fact th at th e s u bs ti tu ti on of int i nto th e fi rs t tem p late fai ls does not m ak e th e ex p res s i on i nv ali d.

T h i s " s u bs ti tu ti on-fai lu re-i s -not-an-error" (SF I N A E ) p ri nci p le i s clearly an i m p ortant i ng redi ent to m ak e th e ov erloadi ng of fu ncti on tem p lates p racti cal. H owev er, i t als o enables rem ark able com p i le-ti m e tech ni q u es . F or ex am p le, as s u m i ng th at typ es RT1 and RT2 are defi ned as follows :

typedef char RT1; typedef struct { char a[2]; } RT2;

W e can ch eck at c ompi le ti me (i n oth er words , as a s o-called c on stan t-ex pr essi on ) wh eth er a g i v en typ e T h as a m em ber typ e X:

#define type_has_member_type_X(T) \ (sizeof(test<T>(0)) == 1)

T o u nders tand th e ex p res s i on i n th i s m acro, i t i s conv eni ent to analyz e from th e ou ts i de to th e i ns i de. F i rs t, th e sizeof ex p res s i on wi ll eq u al one i f th e fi rs t test tem p late (wh i ch retu rns a char of s i z e one) i s s elected. T h e oth er tem p late retu rns a s tru ctu re wi th a s i z e th at i s at leas t two (becau s e i t contai ns an array of s i z e two). I n oth er words , th i s i s a dev i ce to determ i ne as a cons tant-ex p res s i on wh eth er th e fi rs t or s econd tem p late was s elected for th e call test<T>(0). C learly, th e fi rs t tem p late cannot be s elected i f th e g i v en typ e T h as no m em ber typ e X. H owev er, i f th e g i v en typ e has a m em ber typ e X , th en th e fi rs t tem p late i s p referred becau s e ov erload res olu ti on (s ee A p p endi x B ) p refers th e conv ers i on from z ero to a nu ll p oi nter cons tant ov er bi ndi ng an arg u m ent to an elli p s i s p aram eter (elli p s i s p aram eters are th e weak es t k i nd of bi ndi ng from an ov erload res olu ti on p ers p ecti v e). Si m i lar tech ni q u es are ex p lored i n C h ap ter 15 .

Page 143: CPlusPlus Templates The Complete Guide

T h e SF I N A E p ri nci p le p rotects only ag ai ns t attem p ts to create i nv ali d typ es bu t not ag ai ns t attem p ts to ev alu ate i nv ali d ex p res s i ons . T h e followi ng ex am p le i s th erefore i nv ali d C + + :

template<int I> void f(int (&)[24/(4-I)]); template<int I> void f(int (&)[24/(4+I)]); int main() { &f<4>; // ERROR: division by zero (SFINAE doesn't apply) }

T h i s ex am p le i s an error ev en th ou g h th e s econd tem p late s u p p orts th e s u bs ti tu ti on wi th ou t leadi ng to a di v i s i on by z ero. T h i s s ort of error m u s t occu r i n th e ex p res s i on i ts elf and not i n bi ndi ng of an ex p res s i on to a tem p late p aram eter. I ndeed, th e followi ng ex am p le i s v ali d:

template<int N> int g() { return N; } template<int* P> int g() { return *P } int main() { return g<1>(); // 1 cannot be bound to int* parameter, } // but SFINAE principle applies

See Secti on 15 .2.2 on p ag e 266 and Secti on 19 .3 on p ag e 3 5 3 for fu rth er ap p li cati ons of th e SF I N A E p ri nci p le.

8.3.2 Type Arguments

T em p late typ e arg u m ents are th e " v alu es " s p eci fi ed for tem p late typ e p aram eters . M os t com m only u s ed typ es can be u s ed as tem p late arg u m ents , bu t th ere are two ex cep ti ons :

1. L o c a l c l a s s e s a n d e n u m e r a t i o n s ( i n o t h e r w o r d s , t y p e s d e c l a r e d i n a f u n c t i o n d e f i n i t i o n ) c a n n o t b e i n v o l v e d i n t e m p l a t e t y p e a r g u m e n t s .

2 . Ty p e s t h a t i n v o l v e u n n a m e d c l a s s t y p e s o r u n n a m e d e n u m e r a t i o n t y p e s c a n n o t b e t e m p l a t e t y p e a r g u m e n t s ( u n n a m e d c l a s s e s o r e n u m e r a t i o n s t h a t a r e g i v e n a n a m e t h r o u g h a t y p e d e f d e c l a r a t i o n a r e O K ) .

A n ex am p le i llu s trates th es e two ex cep ti ons :

template <typename T> class List { … }; typedef struct { double x, y, z; } Point;

Page 144: CPlusPlus Templates The Complete Guide

typedef enum { red, green, blue } *ColorPtr; int main() { struct Association { int* p; int* q; }; List<Assocation*> error1; // ERROR: local type in template argument List<ColorPtr> error2; // ERROR: unnamed type in template // argument List<Point> ok; // OK: unnamed class type named through // a typedef }

A lth ou g h oth er typ es can, i n g eneral, be u s ed as tem p late arg u m ents , th ei r s u bs ti tu ti on for th e tem p late p aram eters m u s t lead to v ali d cons tru cts :

template <typename T> void clear (T p) { *p = 0; // requires that the unary * be applicable to T } int main() { int a; clear(a); // ERROR: int doesn't support the unary * }

8.3.3 Nontype Arguments

N ontyp e tem p late arg u m ents are th e v alu es s u bs ti tu ted for nontyp e p aram eters . Su ch a v alu e m u s t be one of th e followi ng th i ng s :

• A noth er nontyp e tem p late p aram eter th at h as th e ri g h t typ e • A com p i le-ti m e cons tant v alu e of i nteg er (or enu m erati on) typ e. T h i s i s

accep table only i f th e corres p ondi ng p aram eter h as a typ e th at m atch es th at of th e v alu e, or a typ e to wh i ch th e v alu e can be i m p li ci tly conv erted (for ex am p le, a char can be p rov i ded for an int p aram eter).

• T h e nam e of an ex ternal v ari able or fu ncti on p receded by th e bu i lt-i n u nary & (" addres s of" ) op erator. F or fu ncti ons and array v ari ables , & can be left ou t. Su ch tem p late arg u m ents m atch nontyp e p aram eters of a p oi nter typ e.

• T h e p rev i ou s k i nd of arg u m ent bu t wi th ou t a leadi ng & op erator i s a v ali d arg u m ent for a nontyp e p aram eter of reference typ e.

• A p oi nter-to-m em ber cons tant; i n oth er words , an ex p res s i on of th e form &C::m wh ere C i s a clas s typ e and m i s a nons tati c m em ber (data or fu ncti on). T h i s m atch es nontyp e p aram eters of p oi nter-to-m em ber typ e

Page 145: CPlusPlus Templates The Complete Guide

only.

W h en m atch i ng an arg u m ent to a p aram eter th at i s a p oi nter or reference, u ser -d ef i n ed c on v er si on s (cons tru ctors for one arg u m ent and conv ers i on op erators ) and deri v ed-to-bas e conv ers i ons are not cons i dered, ev en th ou g h i n oth er ci rcu m s tances th ey wou ld be v ali d i m p li ci t conv ers i ons . I m p li ci t conv ers i ons th at m ak e an arg u m ent m ore const or m ore volatile are fi ne.

H ere are s om e v ali d ex am p les of nontyp e tem p late arg u m ents :

template <typename T, T nontype_param> class C; C<int, 33>* c1; // integer type int a; C<int*, &a>* c2; // address of an external variable void f(); void f(int); C<void (*)(int), &f>* c3; // name of a function: overload resolution selects // f(int) in this case; the & is implied class X { int n; static bool b; }; C<bool&, X::b>* c4; // static class members are acceptable variable // and function names C<int X::*, &X::n>* c5; // an example of a pointer-to-member constant template<typename T> void templ_func(); C<void (), &templ_func<double> >* c6; // function template instantiations are functions too

A g eneral cons trai nt of tem p late arg u m ents i s th at a com p i ler or a li nk er m u s t be able to ex p res s th ei r v alu e wh en th e p rog ram i s bei ng bu i lt. V alu es th at aren' t k nown u nti l a p rog ram i s ru n (for ex am p le, th e addres s of local v ari ables ) aren' t com p ati ble wi th th e noti on th at tem p lates are i ns tanti ated wh en th e p rog ram i s bu i lt.

E v en s o, th ere are s om e cons tant v alu es th at are, p erh ap s s u rp ri s i ng ly, not cu rrently v ali d:

• N u ll p oi nter cons tants

Page 146: CPlusPlus Templates The Complete Guide

• F loati ng -p oi nt nu m bers • Stri ng li terals

O ne of th e p roblem s wi th s tri ng li terals i s th at two i denti cal li terals can be s tored at two di s ti nct addres s es . A n alternati v e (bu t cu m bers om e) way to ex p res s tem p lates i ns tanti ated ov er cons tant s tri ng s i nv olv es i ntrodu ci ng an addi ti onal v ari able to h old th e s tri ng :

template <char const* str> class Message; extern char const hello[] = "Hello World!"; Message<hello>* hello_msg;

N ote th e need for th e extern k eyword becau s e oth erwi s e a const array v ari able wou ld h av e i nternal li nk ag e.

See Secti on 4 .3 on p ag e 4 0 for anoth er ex am p le and Secti on 13 .4 on p ag e 209 for a di s cu s s i on of p os s i ble fu tu re ch ang es i n th i s area.

H ere are few oth er (les s s u rp ri s i ng ) i nv ali d ex am p les :

template<typename T, T nontype_param> class C; class Base { int i; } base; class Derived : public Base { } derived_obj; C<Base*, &derived_obj>* err1; // ERROR: derived-to-base conversions are // not considered C<int&, base.i>* err2; // ERROR: fields of variables aren't // considered to be variables int a[10]; C<int*, &a[0]>* err3; // ERROR: addresses of individual array // elements aren't acceptable either

8.3.4 Template Template Arguments

A tem p late tem p late arg u m ent m u s t be a clas s tem p late wi th p aram eters th at ex ac tly m atch th e p aram eters of th e tem p late tem p late p aram eter i t s u bs ti tu tes . D efau lt tem p late arg u m ents of a tem p late tem p late ar g u men t are i g nored (bu t i f

Page 147: CPlusPlus Templates The Complete Guide

th e tem p late tem p late par ameter h as defau lt arg u m ents , th ey are cons i dered du ri ng th e i ns tanti ati on of th e tem p late).

T h i s m ak es th e followi ng ex am p le i nv ali d:

#include <list> // declares: // namespace std { // template <typename T, // typename Allocator = allocator<T> > // class list; // } template<typename T1, typename T2, template<typename> class Container> // Container expects templates with only // one parameter class Relation { public: … private: Container<T1> dom1; Container<T2> dom2; }; int main() { Relation<int, double, std::list> rel; // ERROR: std::list has more than one template parameter … }

T h e p roblem i n th i s ex am p le i s th at th e std::list tem p late of th e s tandard li brary h as m ore th an one p aram eter. T h e s econd p aram eter (wh i ch des cri bes a s o-called alloc ator ) h as a defau lt v alu e, bu t th i s i s not cons i dered wh en m atch i ng std::list to th e Container p aram eter.

Som eti m es , s u ch s i tu ati ons can be work ed arou nd by addi ng a p aram eter wi th a defau lt v alu e to th e tem p late tem p late p aram eter. I n th e cas e of th e p rev i ou s ex am p le, we m ay rewri te th e Relation tem p late as follows :

#include <memory> template<typename T1, typename T2, template<typename T, typename = std::allocator<T> > class Container> // Container now accepts standard container templates class Relation { public: … private: Container<T1> dom1; Container<T2> dom2;

Page 148: CPlusPlus Templates The Complete Guide

};

C learly th i s i s n' t enti rely s ati s factory, bu t i t enables th e u s e of s tandard contai ner tem p lates . Secti on 13 .5 on p ag e 211 di s cu s s es p os s i ble fu tu re ch ang es of th i s top i c.

T h e fact th at s yntacti cally only th e k eyword class can be u s ed to declare a tem p late tem p late p aram eter i s not to be cons tru ed as an i ndi cati on th at only clas s tem p lates declared wi th th e k eyword class are allowed as s u bs ti tu ti ng arg u m ents . I ndeed, " s tru ct tem p lates " and " u ni on tem p lates " are v ali d arg u m ents for a tem p late tem p late p aram eter. T h i s i s s i m i lar to th e obs erv ati on th at (j u s t abou t) any typ e can be u s ed as an arg u m ent for a tem p late typ e p aram eter declared wi th th e k eyword class.

8.3.5 Equivalence

T wo s ets of tem p late arg u m ents are eq u i v alent wh en v alu es of th e arg u m ents are i denti cal one-for-one. F or typ e arg u m ents , typ edef nam es don' t m atter: I t i s th e typ e u lti m ately u nderlyi ng th e typ edef th at i s com p ared. F or i nteg er nontyp e arg u m ents , th e v alu e of th e arg u m ent i s com p ared; h ow th at v alu e i s ex p res s ed does n' t m atter. T h e followi ng ex am p le i llu s trates th i s concep t:

template <typename T, int I> class Mix; typedef int Int; Mix<int, 3*3>* p1; Mix<Int, 4+5>* p2; // p2 has the same type as p1

A fu ncti on g enerated from a fu ncti on tem p late i s nev er eq u i v alent to an ordi nary fu ncti on ev en th ou g h th ey m ay h av e th e s am e typ e and th e s am e nam e. T h i s h as two i m p ortant cons eq u ences for clas s m em bers :

1. A f u n c t i o n g e n e r a t e d f r o m a m e m b e r f u n c t i o n t e m p l a t e n e v e r o v e r r i d e s a v i r t u a l f u n c t i o n . 2 . A c o n s t r u c t o r g e n e r a t e d f r o m a c o n s t r u c t o r t e m p l a t e i s n e v e r a d e f a u l t c o p y c o n s t r u c t o r . ( S i m i l a r l y ,

a n a s s i g n m e n t g e n e r a t e d f r o m a n a s s i g n m e n t t e m p l a t e i s n e v e r a c o p y - a s s i g n m e n t o p e r a t o r . H o w e v e r , t h i s i s l e s s p r o n e t o p r o b l e m s b e c a u s e u n l i k e c o p y c o n s t r u c t o r s , a s s i g n m e n t o p e r a t o r s a r e n e v e r c a l l e d i m p l i c i t l y .)

Page 149: CPlusPlus Templates The Complete Guide

8.4 Friends

T h e bas i c i dea of fri end declarati ons i s a s i m p le one: I denti fy clas s es or fu ncti ons th at h av e a p ri v i leg ed connecti on wi th th e clas s i n wh i ch th e fri end declarati on ap p ears . M atters are s om ewh at com p li cated, h owev er, by two facts :

1. A f r i e n d d e c l a r a t i o n m a y b e t h e o n l y d e c l a r a t i o n o f a n e n t i t y . 2 . A f r i e n d f u n c t i o n d e c l a r a t i o n c a n b e a d e f i n i t i o n .

F ri end clas s declarati ons cannot be defi ni ti ons and th erefore are rarely p roblem ati c. I n th e contex t of tem p lates , th e only new facet of fri end clas s declarati ons i s th e abi li ty to nam e a p arti cu lar i ns tance of a clas s tem p late as a fri end:

template <typename T> class Node; template <typename T> class Tree { friend class Node<T>; … };

N ote th at th e clas s tem p late m u s t be v i s i ble at th e p oi nt wh ere one of i ts i ns tances i s m ade a fri end of a clas s or clas s tem p late. W i th an ordi nary clas s , th ere i s no s u ch req u i rem ent:

template <typename T> class Tree { friend class Factory; // OK, even if first declaration of Factory friend class class Node<T>; // ERROR if Node isn't visible };

Secti on 9 .2.2 on p ag e 125 h as m ore to s ay abou t th i s .

8.4.1 Friend Functions

A n i ns tance of a fu ncti on tem p late can be m ade a fri end by m ak i ng s u re th e nam e of th e fri end fu ncti on i s followed by ang le brack ets . T h e ang le brack ets can contai n th e tem p late arg u m ents , bu t i f th e arg u m ents can be dedu ced, th e ang le brack ets can be left em p ty:

template <typename T1, typename T2> void combine(T1, T2);

Page 150: CPlusPlus Templates The Complete Guide

class Mixer { friend void combine<>(int&, int&); // OK: T1 = int&, T2 = int& friend void combine<int, int>(int, int); // OK: T1 = int, T2 = int friend void combine<char>(char, int); // OK: T1 = char T2 = int friend void combine<char>(char&, int); // ERROR: doesn't match combine() template friend void combine<>(long, long) { … } // ERROR: definition not allowed! };

N ote th at we cannot d ef i n e a tem p late i ns tance (at m os t, we can defi ne a s p eci ali z ati on), and h ence a fri end declarati on th at nam es an i ns tance cannot be a defi ni ti on.

I f th e nam e i s not followed by ang le brack ets , th ere are two p os s i bi li ti es :

1. I f t h e n a m e i s n ' t q u a l i f i e d ( i n o t h e r w o r d s , i t d o e s n ' t c o n t a i n a d o u b l e c o l o n ) , i t n e v e r r e f e r s t o a t e m p l a t e i n s t a n c e . I f n o m a t c h i n g n o n t e m p l a t e f u n c t i o n i s v i s i b l e a t t h e p o i n t o f t h e f r i e n d d e c l a r a t i o n , t h e f r i e n d d e c l a r a t i o n i s t h e f i r s t d e c l a r a t i o n o f t h a t f u n c t i o n . Th e d e c l a r a t i o n c o u l d a l s o b e a d e f i n i t i o n .

2 . I f t h e n a m e is q u a l i f i e d ( i t c o n t a i n s :: ) , t h e n a m e m u s t r e f e r t o a p r e v i o u s l y d e c l a r e d f u n c t i o n o r f u n c t i o n t e m p l a t e . A m a t c h i n g f u n c t i o n i s p r e f e r r e d o v e r a m a t c h i n g f u n c t i o n t e m p l a t e . H o w e v e r , s u c h a f r i e n d d e c l a r a t i o n c a n n o t b e a d e f i n i t i o n .

A n ex am p le m ay h elp clari fy th e v ari ou s p os s i bi li ti es :

void multiply (void*); // ordinary function template <typename T> void multiply(T); // function template class Comrades { friend multiply(int) {} // defines a new function ::multiply(int) friend ::multiply(void*); // refers to the ordinary function above; // not to the multiply<void*> instance friend ::multiply(int); // refers to an instance of the template friend ::multiply<double*>(double*); // qualified names can also have angle brackets // but a template must be visible. friend ::error() {} // ERROR: a qualified friend cannot be a definition };

I n ou r p rev i ou s ex am p les , we declared th e fri end fu ncti ons i n an ordi nary clas s .

Page 151: CPlusPlus Templates The Complete Guide

T h e s am e ru les ap p ly wh en we declare th em i n clas s tem p lates , bu t th e tem p late p aram eters m ay p arti ci p ate i n i denti fyi ng th e fu ncti on th at i s to be a fri end:

template <typename T> class Node { Node<T>* allocate(); … }; template <typename T> class List { friend Node<T>* Node<T>::allocate(); … };

H owev er, an i nteres ti ng effect occu rs wh en a fri end fu ncti on i s d ef i n ed i n a clas s tem p late becau s e anyth i ng th at i s only declared i n a tem p late i s n' t a concrete enti ty u nti l th e tem p late i s i ns tanti ated. C ons i der th e followi ng ex am p le:

template <typename T> class Creator { friend void appear() { // a new function ::appear(), but it doesn't … // exist until Creator is instantiated } }; Creator<void> miracle; // ::appear() is created at this point Creator<double> oops; // ERROR: ::appear() is created a second time!

I n th i s ex am p le, two di fferent i ns tanti ati ons create two i denti cal defi ni ti ons —a di rect v i olati on of th e O D R (s ee A p p endi x A ).

W e m u s t th erefore m ak e s u re th e tem p late p aram eters of th e clas s tem p late ap p ear i n th e typ e of any fri end fu ncti on defi ned i n th at tem p late (u nles s we want to p rev ent m ore th an one i ns tanti ati on of a clas s tem p late i n a p arti cu lar fi le, bu t th i s i s rath er u nli k ely). L et' s ap p ly th i s to a v ari ati on of ou r p rev i ou s ex am p le:

template <typename T> class Creator { friend void feed(Creator<T>*){ // every T generates a different … // function ::feed() } }; Creator<void> one; // generates ::feed(Creator<void>*) Creator<double> two; // generates ::feed(Creator<double>*)

I n th i s ex am p le, ev ery i ns tanti ati on of Creator g enerates a di fferent fu ncti on. N ote th at ev en th ou g h th es e fu ncti ons are g enerated as p art of th e i ns tanti ati on

Page 152: CPlusPlus Templates The Complete Guide

of a tem p late, th e fu ncti ons th em s elv es are ordi nary fu ncti ons , not i ns tances of a tem p late.

A ls o note th at becau s e th e body of th es e fu ncti ons i s defi ned i ns i de a clas s defi ni ti on, th ey are i m p li ci tly i nli ne. H ence, i t i s not an error for th e s am e fu ncti on to be g enerated i n two di fferent trans lati on u ni ts . Secti on 9 .2.2 on p ag e 125 and Secti on 11.7 on p ag e 17 4 h av e m ore to s ay abou t th i s top i c.

8.4.2 Friend Templates

U s u ally wh en declari ng a fri end th at i s an i ns tance of a fu ncti on or a clas s tem p late, we can ex p res s ex actly wh i ch enti ty i s to be th e fri end. Som eti m es i t i s noneth eles s u s efu l to ex p res s th at all i ns tances of a tem p late are fri ends of a clas s . T h i s req u i res a s o-called f r i en d template. F or ex am p le:

class Manager { template<typename T> friend class Task; template<typename T> friend void Schedule<T>::dispatch(Task<T>*); template<typename T> friend int ticket() { return ++Manager::counter; } static int counter; };

J u s t as wi th ordi nary fri end declarati ons a fri end tem p late can be a defi ni ti on only i f i t nam es an u nq u ali fi ed fu ncti on nam e th at i s not followed by ang le brack ets .

A fri end tem p late can declare only p ri m ary tem p lates and m em bers of p ri m ary tem p lates . A ny p arti al s p eci ali z ati ons and ex p li ci t s p eci ali z ati ons as s oci ated wi th a p ri m ary tem p late are au tom ati cally cons i dered fri ends too.

Page 153: CPlusPlus Templates The Complete Guide

8.5 Afternotes

T h e g eneral concep t and s yntax of C + + tem p lates h av e rem ai ned relati v ely s table s i nce th ei r i ncep ti on i n th e late 19 8 0s . C las s tem p lates and fu ncti on tem p lates were p art of th e i ni ti al tem p late faci li ty. So were typ e p aram eters and nontyp e p aram eters .

H owev er, th ere were als o s om e s i g ni fi cant addi ti ons to th e ori g i nal des i g n, m os tly dri v en by th e needs of th e C + + s tandard li brary. M em ber tem p lates m ay well be th e m os t fu ndam ental of th os e addi ti ons . C u ri ou s ly, only m em ber f u n c ti on tem p lates were form ally v oted i nto th e C + + s tandard. M em ber c lass tem p lates becam e p art of th e s tandard by an edi tori al ov ers i g h t.

F ri end tem p lates , defau lt tem p late arg u m ents , and tem p late tem p late p aram eters are als o relati v ely recent addi ti ons to th e lang u ag e. T h e abi li ty to declare tem p late tem p late p aram eters i s s om eti m es called hi g her -or d er g en er i c i ty . T h ey were ori g i nally i ntrodu ced to s u p p ort a certai n allocator m odel i n th e C + + s tandard li brary, bu t th at allocator m odel was later rep laced by one th at does not rely on tem p late tem p late p aram eters . L ater, tem p late tem p late p aram eters cam e clos e to bei ng rem ov ed from th e lang u ag e becau s e th ei r s p eci fi cati on h ad rem ai ned i ncom p lete u nti l v ery late i n th e s tandardi z ati on p roces s . E v entu ally a m aj ori ty of com m i ttee m em bers v oted to k eep th em and th ei r s p eci fi cati ons were com p leted.

Page 154: CPlusPlus Templates The Complete Guide

Chapter 9. Names in Templates

N am es are a fu ndam ental concep t i n m os t p rog ram m i ng lang u ag es . T h ey are th e m eans by wh i ch a p rog ram m er can refer to p rev i ou s ly cons tru cted enti ti es . W h en a C + + com p i ler encou nters a nam e, i t m u s t " look i t u p " to i denti fy to wh i ch enti ty i s bei ng referred. F rom an i m p lem enter' s p oi nt of v i ew, C + + i s a h ard lang u ag e i n th i s res p ect. C ons i der th e C + + s tatem ent x*y; .I fx and y are th e nam es of v ari ables , th i s s tatem ent i s a m u lti p li cati on, bu t i f x i s th e nam e of a typ e, th en th e s tatem ent declares y as a p oi nter to an enti ty of typ e x.

T h i s s m all ex am p le dem ons trates th at C + + (li k e C ) i s a s o-called c on tex t-sen si ti v e lan g u ag e: A cons tru ct cannot always be u nders tood wi th ou t k nowi ng i ts wi der contex t. H ow does th i s relate to tem p lates ? W ell, tem p lates are cons tru cts th at m u s t deal wi th m u lti p le wi der contex ts : (1) th e contex t i n wh i ch th e tem p late ap p ears , (2) th e contex t i n wh i ch th e tem p late i s i ns tanti ated, and (3 ) th e contex ts as s oci ated wi th th e tem p late arg u m ents for wh i ch th e tem p late i s i ns tanti ated. H ence i t s h ou ld not be totally s u rp ri s i ng th at " nam es " m u s t be dealt wi th q u i te carefu lly i n C + + .

Page 155: CPlusPlus Templates The Complete Guide

9.1 Name Taxonomy

C + + clas s i fi es nam es i n a v ari ety of ways —a larg e v ari ety of ways i n fact. T o h elp cop e wi th th i s abu ndance of term i nolog y, we p rov i de tables T able 9 .1 and T able 9 .2, wh i ch des cri be th es e clas s i fi cati ons . F ortu nately, you can g ai n g ood i ns i g h t i nto m os t C + + tem p late i s s u es by fam i li ari z i ng you rs elf wi th two m aj or nam i ng concep ts :

1. A n a m e i s a q u a l i f i e d n a m e i f t h e s c o p e t o w h i c h i t b e l o n g s i s e x p l i c i t l y d e n o t e d u s i n g a s c o p e r e s o l u t i o n o p e r a t o r ( :: ) o r a m e m b e r a c c e s s o p e r a t o r ( . o r -> ) . F o r e x a m p l e , this->count i s a q u a l i f i e d n a m e , b u t count i s n o t ( e v e n t h o u g h t h e p l a i n count m i g h t a c t u a l l y r e f e r t o a c l a s s m e m b e r ) .

2 . A n a m e i s a d e p e n d e n t n a m e i f i t d e p e n d s i n s o m e w a y o n a t e m p l a t e p a r a m e t e r . F o r e x a m p l e , std::vector<T>::iterator i s a d e p e n d e n t n a m e i f T i s a t e m p l a t e p a r a m e t e r , b u t i t i s a n o n d e p e n d e n t n a m e i f T i s a k n o w n t y p e d e f ( f o r e x a m p l e , o f int) .

Table 9.1. Name Taxonomy (part one) C las s i f i c ati on E xplanati on and Notes I denti fi er A nam e th at cons i s ts s olely of an u ni nterru p ted s eq u ences of

letters , u nders cores (_) and di g i ts . I t cannot s tart wi th a di g i t, and s om e i denti fi ers are res erv ed for th e i m p lem entati on: Y ou s h ou ld not i ntrodu ce th em i n you r p rog ram s (as a ru le of th u m b, av oi d leadi ng u nders cores and dou ble u nders cores ). T h e concep t of " letter" s h ou ld be tak en broadly and i nclu des s p eci al u n i v er sal c har ac ter n ames ( U CNs) th at encode g lyp h s from nonalp h abeti cal lang u ag es .

O p erator-fu ncti on-i d

T h e k eyword operator followed by th e s ym bol for an op erator— for ex am p le, operator new and operator [ ]. M any op erators h av e alternati v e rep res entati ons . F or ex am p le, operator & can eq u i v alently be wri tten as operator bitand ev en wh en i t denotes th e u nary ad d r ess of op erator.

C onv ers i on-fu ncti on-i d

U s ed to denote u s er-defi ned i m p li ci t conv ers i on op erator—for ex am p le operator int& , wh i ch cou ld als o be obfu s cated as operator int bitand.

T em p late-i d T h e nam e of a tem p late followed by tem p late arg u m ents enclos ed i n ang le brack ets ; for ex am p le, List<T, int, 0>. (Stri ctly s p eak i ng , th e C + + s tandard allows only s i m p le i denti fi ers for th e tem p late nam e of a tem p late-i d. H owev er, th i s i s p robably an ov ers i g h t and an op erator-fu ncti on-i d s h ou ld be allowed too; e.g . operator+<X<int> >.)

U nq u ali fi ed-i d T h e g enerali z ati on of an i denti fi er. I t can be any of th e abov e (i denti fi er, op erator-fu ncti on-i d, conv ers i on-fu ncti on-i d or

Page 156: CPlusPlus Templates The Complete Guide

(i denti fi er, op erator-fu ncti on-i d, conv ers i on-fu ncti on-i d or tem p late-i d) or a " des tru ctor nam e" (for ex am p le, notati ons li k e ~Data or ~List<T, T, N>).

Q u ali fi ed-i d A n u nq u ali fi ed-i d th at i s q u ali fi ed wi th th e nam e of a clas s or nam es p ace, or j u s t wi th th e g lobal s cop e res olu ti on op erator. N ote th at s u ch a nam e i ts elf can be q u ali fi ed. E x am p les are ::X , S::x, Array<T>::y, and ::N::A<T>::z.

Q u ali fi ed nam e T h i s term i s not defi ned i n th e s tandard, bu t we u s e i t to refer to nam es th at u nderg o s o-called q u ali f i ed look u p. Sp eci fi cally, th i s i s a q u ali fi ed-i d or an u nq u ali fi ed-i d th at i s u s ed after an ex p li ci t m em ber acces s op erator (. or ->). E x am p les are S::x , this->f, and p->A::m. H owev er, j u s t class_mem i n a contex t th at i s i m p li ci tly eq u i v alent to this->class_mem i s not a q u ali fi ed nam e: T h e m em ber acces s m u s t be ex p li ci t.

U nq u ali fi ed nam e

A n u nq u ali fi ed-i d th at i s not a q u ali fi ed nam e. T h i s i s not a s tandard term bu t corres p onds to nam es th at u nderg o wh at th e s tandard calls u n q u ali f i ed look u p.

Table 9.2 . Name Taxonomy (part tw o) C las s i f i c ati on E xplanati on and Notes N am e E i th er a q u ali fi ed or an u nq u ali fi ed nam e. D ep endent nam e

A nam e th at dep ends i n s om e way on a tem p late p aram eter. C ertai nly any q u ali fi ed or u nq u ali fi ed nam e th at ex p li ci tly contai ns a tem p late p aram eter i s dep endent. F u rth erm ore, a q u ali fi ed nam e th at i s q u ali fi ed by a m em ber acces s op erator (. or ->) i s dep endent i f th e typ e of th e ex p res s i on on th e left of th e acces s op erator dep ends on a tem p late p aram eter. I n p arti cu lar, b i n this->b i s a dep endent nam e wh en i t ap p ears i n a tem p late. F i nally, th e i denti fi er ident i n a call of th e form ident(x, y, z) i s a dep endent nam e i f and only i f any of th e arg u m ent ex p res s i ons h as a typ e th at dep ends on a tem p late p aram eter.

N ondep endent nam e

A nam e th at i s not a dep endent nam e by th e abov e des cri p ti on.

I t i s u s efu l to read th rou g h th e tables to g ai n s om e fam i li ari ty wi th th e term s th at are s om eti m es u s ed to des cri be C + + tem p late i s s u es , bu t i t i s not es s enti al to rem em ber th e ex act m eani ng of ev ery term . Sh ou ld th e need ari s e, th ey can be eas i ly fou nd i n th e i ndex .

Page 157: CPlusPlus Templates The Complete Guide
Page 158: CPlusPlus Templates The Complete Guide

9.2 Looking Up Names

T h ere are m any s m all detai ls to look i ng u p nam es i n C + + , bu t we wi ll focu s only on a few m aj or concep ts . T h e detai ls are neces s ary to ens u re only th at (1) norm al cas es are treated i ntu i ti v ely, and (2) p ath olog i cal cas es are cov ered i n s om e way by th e s tandard.

Q u ali fi ed nam es are look ed u p i n th e s cop e i m p li ed by th e q u ali fyi ng cons tru ct. I f th at s cop e i s a clas s , th en bas e clas s es m ay als o be look ed u p . H owev er, enclos i ng s cop es are not cons i dered wh en look i ng u p q u ali fi ed nam es . T h e followi ng i llu s trates th i s bas i c p ri nci p le:

int x; class B { public: int i; }; class D : public B { }; void f(D* pd) { pd->i = 3; // finds B::i D::x = 2; // ERROR: does not find ::x in the enclosing scope }

I n contras t, u nq u ali fi ed nam es are typ i cally look ed u p i n s u cces s i v ely m ore enclos i ng s cop es (alth ou g h i n m em ber fu ncti on defi ni ti ons th e s cop e of th e clas s and i ts bas e clas s es i s s earch ed before any oth er enclos i ng s cop es ). T h i s i s called or d i n ar y look u p. H ere i s a bas i c ex am p le s h owi ng th e m ai n i dea u nderlyi ng ordi nary look u p :

extern int count; // (1) int lookup_example(int count) // (2) { if (count < 0) { int count = 1; // (3) lookup_example(count); // unqualified count refers to (3) } return count + ::count; // the first (unqualified) count refers to (2); } // the second (qualified) count refers to (1)

A m ore recent twi s t to th e look u p of u nq u ali fi ed nam es i s th at—i n addi ti on to ordi nary look u p —th ey m ay s om eti m es u nderg o s o-called ar g u men t-d epen d en t

[1]

Page 159: CPlusPlus Templates The Complete Guide

look u p (AD L ). [1] B efore p roceedi ng wi th th e detai ls of A D L , let' s m oti v ate th e m ech ani s m wi th ou r p erenni al max() tem p late:

[1] T h i s i s als o called K oen i g look u p (or ex ten d ed K oen i g look u p) after A ndrew K oeni g , wh o fi rs t p rop os ed a v ari ati on of th i s m ech ani s m .

template <typename T> inline T const& max (T const& a, T const& b) { return a < b ? b : a; }

Su p p os e now th at we need to ap p ly th i s tem p late to a typ e defi ned i n anoth er nam es p ace:

namespace BigMath { class BigNumber { … }; bool operator < (BigNumber const&, BigNumber const&); … } using BigMath::BigNumber; void g (BigNumber const& a, BigNumber const& b) { … BigNumber x = max(a,b); … }

T h e p roblem h ere i s th at th e max() tem p late i s u naware of th e BigMath nam es p ace, bu t ordi nary look u p wou ld not fi nd th e op erator < ap p li cable to v alu es of typ e BigNumber. W i th ou t s om e s p eci al ru les , th i s g reatly redu ces th e ap p li cabi li ty of tem p lates i n th e contex t of C + + nam es p aces . A D L i s th e C + + ans wer to th os e " s p eci al ru les ."

9.2.1 Argument-Dependent Lookup

A D L ap p li es only to u nq u ali fi ed nam es th at look li k e th ey nam e a nonm em ber fu ncti on i n a fu ncti on call. I f ordi nary look u p fi nds th e nam e of a m em ber fu ncti on or th e nam e of a typ e, th en A D L does not h ap p en. A D L i s als o i nh i bi ted i f th e nam e of th e fu ncti on to be called i s enclos ed i n p arenth es es .

O th erwi s e, i f th e nam e i s followed by a li s t of arg u m ent ex p res s i ons enclos ed i n p arenth es es , A D L p roceeds by look i ng u p th e nam e i n nam es p aces and clas s es " as s oci ated wi th " th e typ es of th e call arg u m ents . T h e p reci s e defi ni ti on of th es e assoc i ated n amespac es and assoc i ated c lasses i s g i v en later, bu t i ntu i ti v ely th ey

Page 160: CPlusPlus Templates The Complete Guide

can be th ou g h t as bei ng all th e nam es p aces and clas s es th at are fai rly di rectly connected to a g i v en typ e. F or ex am p le, i f th e typ e i s a p oi nter to a clas s X, th en th e as s oci ated clas s es and nam es p ace wou ld i nclu de X as well as any nam es p aces or clas s es to wh i ch X belong s .

T h e p reci s e defi ni ti on of th e s et of assoc i ated n amespac es and assoc i ated c lasses for a g i v en typ e i s determ i ned by th e followi ng ru les :

• F or bu i lt-i n typ es , th i s i s th e em p ty s et. • F or p oi nter and array typ es , th e s et of as s oci ated nam es p aces and clas s es

i s th at of th e u nderlyi ng typ e. • F or enu m erati on typ es , th e as s oci ated nam es p ace i s th e nam es p ace i n

wh i ch th e enu m erati on i s declared. F or clas s m em bers , th e enclos i ng clas s i s th e as s oci ated clas s .

• F or clas s typ es (i nclu di ng u ni on typ es ) th e s et of as s oci ated clas s es i s th e typ e i ts elf, th e enclos i ng clas s , and any di rect and i ndi rect bas e clas s es . T h e s et of as s oci ated nam es p aces i s th e nam es p aces i n wh i ch th e as s oci ated clas s es are declared. I f th e clas s i s a clas s tem p late i ns tanti ati on, th en th e typ es of th e tem p late typ e arg u m ents and th e clas s es and nam es p aces i n wh i ch th e tem p late tem p late arg u m ents are declared are als o i nclu ded.

• F or fu ncti on typ es , th e s ets of as s oci ated nam es p aces and clas s es com p ri s e th e nam es p aces and clas s es as s oci ated wi th all th e p aram eter typ es and th os e as s oci ated wi th th e retu rn typ e.

• F or p oi nter-to-m em ber-of-clas s -X typ es , th e s ets of as s oci ated nam es p aces and clas s es i nclu de th os e as s oci ated wi th X i n addi ti on to th os e as s oci ated wi th th e typ e of th e m em ber. (I f i t i s a p oi nter-to-m em ber-fu ncti on typ e, th en th e p aram eter and retu rn typ es can contri bu te too.)

A D L th en look s u p th e nam e i n all th e as s oci ated nam es p aces as i f th e nam e h ad been q u ali fi ed wi th each of th es e nam es p aces i n tu rn, ex cep t th at u s i ng -di recti v es are i g nored. T h e followi ng ex am p le i llu s trates th i s :

// details/adl.cpp #include <iostream> namespace X { template<typename T> void f(T); } namespace N { using namespace X; enumE{e1}; void f(E) { std::cout << "N::f(N::E) called\n";

Page 161: CPlusPlus Templates The Complete Guide

} } void f(int) { std::cout << "::f(int) called\n"; } int main() { ::f(N::e1); // qualified function name: no ADL f(N::e1); // ordinary lookup finds ::f() and ADL finds N::f(), } // the latter is preferred

N ote th at i n th i s ex am p le, th e u s i ng -di recti v e i n nam es p ace N i s i g nored wh en A D L i s p erform ed. H ence X::f() i s nev er ev en a candi date for th e call i n main().

9.2.2 Friend Name Injection

A fri end fu ncti on declarati on can be th e fi rs t declarati on of th e nom i nated fu ncti on. I f th i s i s th e cas e, th en th e fu ncti on i s as s u m ed to be declared i n th e neares t nam es p ace s cop e (or p erh ap s th e g lobal s cop e) enclos i ng th e clas s contai ni ng th e fri end declarati on. A relati v ely controv ers i al i s s u e i s wh eth er th at declarati on s h ou ld be v i s i ble i n th e s cop e i n wh i ch i t i s " i nj ected." I t i s m os tly a p roblem wi th tem p lates . C ons i der th e followi ng ex am p le:

template<typename T> class C { … friend void f(); friend void f(C<T> const&); … }; void g (C<int>* p) { f(); // Is f() visible here? f(*p); // Is f(C<int> const&) visible here? }

T h e trou ble i s th at i f fri end declarati ons are v i s i ble i n th e enclos i ng nam es p ace, th en i ns tanti ati ng a clas s tem p late m ay m ak e v i s i ble th e declarati on of ordi nary fu ncti ons . Som e p rog ram m ers fi nd th i s s u rp ri s i ng , and th e C + + s tandard th erefore s p eci fi es th at fri end declarati ons do not ordi nari ly m ak e th e nam e v i s i ble i n th e enclos i ng s cop e.

H owev er, th ere i s an i nteres ti ng p rog ram m i ng tech ni q u e th at dep ends on declari ng (and defi ni ng ) a fu ncti on i n a fri end declarati on only (s ee Secti on 11.7 on p ag e 17 4 ). T h erefore th e s tandard als o s p eci fi es th at fri end fu ncti ons are fou nd wh en th e clas s of wh i ch th ey are a fri end i s am ong th e as s oci ated clas s es

Page 162: CPlusPlus Templates The Complete Guide

cons i dered by A D L .

R econs i der ou r las t ex am p le. T h e call f() h as no as s oci ated clas s es or nam es p aces becau s e th ere are no arg u m ents : I t i s an i nv ali d call i n ou r ex am p le. H owev er, th e call f(*p) does h av e th e as s oci ated clas s C<int> (becau s e th i s i s th e typ e of *p), and th e g lobal nam es p ace i s als o as s oci ated (becau s e th i s i s th e nam es p ace i n wh i ch th e typ e of *p i s declared). T h erefore th e s econd fri end fu ncti on declarati on cou ld be fou nd p rov i ded th e clas s C<int> was actu ally fu lly i ns tanti ated p ri or to th e call. T o ens u re th i s , i t i s as s u m ed th at a call i nv olv i ng a look u p for fri ends i n as s oci ated clas s es actu ally cau s es th e clas s to be i ns tanti ated (i f not done already). [2]

[2] A lth ou g h th i s was clearly i ntended by th os e wh o wrote th e C + + s tandard, i t i s not clearly s p elled ou t i n th e s tandard.

9.2.3 Injected Class Names

T h e nam e of a clas s i s " i nj ected" i ns i de th e s cop e of th at clas s i ts elf and i s th erefore acces s i ble as an u nq u ali fi ed nam e i n th at s cop e. (H owev er, i t i s not acces s i ble as a q u ali fi ed nam e becau s e th i s i s th e notati on u s ed to denote th e cons tru ctors .) F or ex am p le:

// details/inject.cpp #include <iostream> int C; class C { private: int i[2]; public: static int f() { return sizeof(C); } }; int f() { return sizeof(C); } int main() { std::cout << "C::f() = " <<C::f() << "," << " ::f() = " <<::f() << std::endl; }

T h e m em ber fu ncti on C::f() retu rns th e s i z e of typ e C wh ereas th e fu ncti on ::f() retu rns th e s i z e of th e v ari able C (i n oth er words , th e s i z e of an int

Page 163: CPlusPlus Templates The Complete Guide

obj ect).

C las s tem p lates als o h av e i nj ected clas s nam es . H owev er, th ey' re s trang er th an ordi nary i nj ected clas s nam es : T h ey can be followed by tem p late arg u m ents (i n wh i ch cas e th ey are i nj ected clas s template nam es ), bu t i f th ey are not followed by tem p late arg u m ents th ey rep res ent th e clas s wi th i ts p aram eters as i ts arg u m ents (or, for a p arti al s p eci ali z ati on, i ts s p eci ali z ati on arg u m ents ). T h i s ex p lai ns th e followi ng s i tu ati on:

template<template<typename> class TT> class X { }; template<typename T> class C { Ca; // OK: same as ''C<T> a;'' C<void> b; // OK X<C> c; // ERROR: C without a template argument list // does not denote a template X<::C> d; // ERROR: <: is an alternative token for [ X< ::C> e; // OK: the space between < and :: is required }

N ote h ow th e u nq u ali fi ed nam e refers to th e i nj ected nam e and i s not cons i dered th e nam e of th e tem p late i f i t i s not followed by a li s t of tem p late arg u m ents . T o com p ens ate, we can force th e nam e of th e tem p late to be fou nd by u s i ng th e fi le s cop e q u ali fi er ::. T h i s work s , bu t we m u s t th en be carefu l not to create a s o-called d i g r aph tok en <:, wh i ch i s i nterp reted as a left brack et. A lth ou g h relati v ely rare, s u ch errors res u lt i n p erp lex i ng di ag nos ti cs .

Page 164: CPlusPlus Templates The Complete Guide

9.3 Parsing Templates

T wo fu ndam ental acti v i ti es of com p i lers for m os t p rog ram m i ng lang u ag es are tok en i z ati on —als o called sc an n i n g or lex i n g —and p ars i ng . T h e tok eni z ati on p roces s reads th e s ou rce code as a s eq u ence of ch aracters and g enerates a s eq u ence of tok ens from i t. F or ex am p le, on s eei ng th e s eq u ence of ch aracters int* p=0;, th e " tok eni z er" wi ll g enerate tok en des cri p ti ons for a k eyword int , a s ym bol/op erator * , an i denti fi er p, a s ym bol/op erator = , an i nteg er li teral 0 , and a s ym bol/op erator ;.

A p ars er wi ll th en fi nd k nown p atterns i n th e tok en s eq u ence by recu rs i v ely redu ci ng tok ens or p rev i ou s ly fou nd p atterns i nto h i g h er lev el cons tru cts . F or ex am p le, th e tok en 0 i s a v ali d ex p res s i on, th e com bi nati on * followed by an i denti fi er p i s a v ali d declarator, and th at declarator followed by " =" followed by th e ex p res s i on " 0" i s als o a v ali d declarator. F i nally, th e k eyword int i s a k nown typ e nam e, and, wh en followed by th e declarator *p=0 , you g et th e i ni ti ali z ati ng declarati on of p.

9.3.1 Context Sensitivity in Nontemplates

A s you m ay k now or ex p ect, tok eni z i ng i s eas i er th an p ars i ng . F ortu nately, p ars i ng i s a s u bj ect for wh i ch a s oli d th eory h as been dev elop ed, and m any u s efu l lang u ag es are not h ard to p ars e u s i ng th i s th eory. H owev er, th e th eory work s bes t for s o-called c on tex t-f r ee lan g u ag e , and we h av e already noted th at C + + i s contex t s ens i ti v e. T o h andle th i s , a C + + com p i ler wi ll cou p le a s ym bol table to th e tok eni z er and p ars er: W h en a declarati on i s p ars ed, i t i s entered i n th e s ym bol table. W h en th e tok eni z er fi nds an i denti fi er, i t look s i t u p and annotates th e res u lti ng tok en i f i t fi nds a typ e.

F or ex am p le, i f th e C + + com p i ler s ees

x*

th e tok eni z er look s u p x. I f i t fi nds a typ e, th e p ars er s ees

identifier, type, x symbol, *

and conclu des th at a declarati on h as s tarted. H owev er, i f x i s not fou nd to be a typ e, th en th e p ars er recei v es from th e tok eni z er

Page 165: CPlusPlus Templates The Complete Guide

identifier, nontype, x symbol, *

and th e cons tru ct can be p ars ed v ali dly only as a m u lti p li cati on. T h e detai ls of th es e p ri nci p les are dep endent on th e p arti cu lar i m p lem entati on s trateg y, bu t th e g i s t s h ou ld be th ere.

A noth er ex am p le of contex t s ens i ti v i ty i s i llu s trated i n th e followi ng ex p res s i on:

X<1>(0)

I f X i s th e nam e of a clas s tem p late, th en th e p rev i ou s ex p res s i on cas ts th e i nteg er 0 to th e typ e X<1> g enerated from th at tem p late. I f X i s not a tem p late, th en th e p rev i ou s ex p res s i on i s eq u i v alent to

(X<1)>0

I n oth er words , X i s com p ared wi th 1, and th e res u lt of th at com p ari s on—tru e or fals e, i m p li ci tly conv erted to 1 or 0 i n th i s cas e—i s com p ared wi th 0. A lth ou g h code li k e th i s i s rarely u s ed, i t i s v ali d C + + (and v ali d C , for th at m atter). A C + + p ars er wi ll th erefore look u p nam es ap p eari ng before a < and treat th e < as an ang le brack et only i f th e nam e i s th at of a tem p late; oth erwi s e, th e < i s an ordi nary " les s th an" op erator.

T h i s form of contex t s ens i ti v i ty i s an u nfortu nate cons eq u ence of h av i ng ch os en ang le brack ets to deli m i t tem p late arg u m ent li s ts . H ere i s anoth er s u ch cons eq u ence:

template<bool B> class Invert { public: static bool const result = !B; }; void g() { bool test = B<(1>0)>::result; // parentheses required! }

I f th e p arenth es es i n B<(1>0)> were om i tted, th e " larg er th an" s ym bol wou ld be m i s tak en for th e clos i ng of th e tem p late arg u m ent li s t. T h i s wou ld m ak e th e code i nv ali d becau s e th e com p i ler wou ld read i t to be eq u i v alent to ((B<1>))0>::result. [3 ]

[3 ] N ote th e dou ble p arenth es es to av oi d p ars i ng (B<1>)0 as a cas t

Page 166: CPlusPlus Templates The Complete Guide

op erati on—yet anoth er s ou rce of s yntacti c am bi g u i ty.

T h e tok eni z er i s n' t s p ared p roblem s wi th th e ang le-brack et notati on ei th er. W e h av e already cau ti oned (s ee Secti on 3 .2 on p ag e 27 ) to i ntrodu ce wh i tes p ace wh en nes ti ng tem p late-i ds , as i n

List<List<int> > a; // ^-- whitespace is not optional!

I ndeed, th e wh i tes p ace between th e two clos i ng ang le brack ets i s not op ti onal: W i th ou t th i s wh i tes p ace, th e two > ch aracters com bi ne i nto a ri g h t s h i ft tok en >> , and h ence are nev er treated as two s ep arate tok ens . T h i s i s a cons eq u ence of th e s o-called max i mu m mu n c h tok eni z ati on p ri nci p le: A C + + i m p lem entati on m u s t collect as m any cons ecu ti v e ch aracters as p os s i ble i nto a tok en.

T h i s p arti cu lar i s s u e i s a v ery com m on s tu m bli ng block for beg i nni ng tem p late u s ers . Sev eral C + + com p i ler i m p lem entati ons h av e th erefore been m odi fi ed to recog ni z e th i s s i tu ati on and treat th e >> as two s ep arate > i n thi s par ti c u lar si tu ati on (and wi th a warni ng th at i t i s not really v ali d C + + ). T h e C + + com m i ttee i s als o cons i deri ng m andati ng th i s beh av i or i n a rev i s i on of th e s tandard (s ee Secti on 13 .1 on p ag e 205 ).

A noth er ex am p le of th e m ax i m u m m u nch p ri nci p le i s th e les s k nown fact th at th e s cop e res olu ti on op erator (::) m u s t als o be u s ed carefu lly wi th ang le brack ets :

class X { … }; List<::X> many_X; // SYNTAX ERROR!

T h e p roblem i n th e p rev i ou s ex am p le i s th at th e s eq u ence of ch aracters <: i s a s o-called d i g r aph [4]: an alternati v e rep res entati on for th e s ym bol [. H ence, th e com p i ler really s ees th e eq u i v alent of List[:X> many_X; , wh i ch m ak es no s ens e at all. A g ai n, th e s olu ti on i s to add s om e wh i tes p ace:

[4] D i g rap h s were added to th e lang u ag e to eas e th e i np u t of C + + s ou rce wi th i nternati onal k eyboards th at lack certai n ch aracters (s u ch as #, [ , and ]).

List< ::X> many_X; // ^-- whitespace is not optional!

9.3.2 Dependent Names of Types

T h e p roblem wi th nam es i n tem p lates i s th at th ey cannot always be s u ffi ci ently

Page 167: CPlusPlus Templates The Complete Guide

clas s i fi ed. I n p arti cu lar, one tem p late cannot look i nto anoth er tem p late becau s e th e contents of th at oth er tem p late can be m ade i nv ali d by an ex pli c i t spec i ali z ati on (s ee C h ap ter 12 for detai ls ). T h e followi ng contri v ed ex am p le i llu s trates th i s :

template<typename T> class Trap { public: enum{x}; // (1) x is not a type here }; template<typename T> class Victim { public: int y; void poof() { Trap<T>::x*y; // (2) declaration or multiplication? } }; template<> class Trap<void> { // evil specialization! public: typedef int x; // (3) x is a type here }; void boom(Trap<void>& bomb) { bomb.poof(); }

A s th e com p i ler i s p ars i ng li ne (2), i t m u s t deci de wh eth er i t i s s eei ng a declarati on or a m u lti p li cati on. T h i s deci s i on i n tu rn dep ends on wh eth er th e dep endent q u ali fi ed nam e Trap<T>::x i s a typ e nam e. I t m ay be tem p ti ng to look i n th e tem p late Trap at th i s p oi nt and fi nd th at, accordi ng to li ne (1), Trap<T>::x i s not a typ e, wh i ch wou ld leav e u s to beli ev e th at li ne (2) i s a m u lti p li cati on. H owev er, a li ttle later th e s ou rce corru p ts th i s i dea by ov erri di ng th e g eneri c X<T>::x for th e cas e wh ere T i s void. I n th i s cas e, Trap<T>::x i s i n fact typ e int.

T h e lang u ag e defi ni ti on res olv es th i s p roblem by s p eci fyi ng th at i n g eneral a dep endent q u ali fi ed nam e does n ot denote a typ e u nles s th at nam e i s p refi x ed wi th th e k eyword typename. I f i t tu rns ou t, after s u bs ti tu ti ng tem p late arg u m ents , th at th e nam e i s not th e nam e of a typ e, th e p rog ram i s i nv ali d and you r C + + com p i ler s h ou ld com p lai n at i ns tanti ati on ti m e. N ote th at th i s u s e of typename i s di fferent from th e u s e to denote tem p late typ e p aram eters . U nli k e typ e p aram eters , you cannot eq u i v alently rep lace typename wi th class. T h e typename p refi x to a nam e i s r eq u i r ed wh en th e nam e

1. A p p e a r s i n a t e m p l a t e

Page 168: CPlusPlus Templates The Complete Guide

2 . I s q u a l i f i e d 3 . I s n o t u s e d a s i n a l i s t o f b a s e c l a s s s p e c i f i c a t i o n s o r i n a l i s t o f m e m b e r i n i t i a l i z e r s i n t r o d u c i n g a

c o n s t r u c t o r d e f i n i t i o n 4 . I s d e p e n d e n t o n a t e m p l a t e p a r a m e t e r

F u rth erm ore, th e typename p refi x i s n ot allow ed u nles s at leas t th e fi rs t th ree p rev i ou s condi ti ons h old. T o i llu s trate th i s , cons i der th e followi ng erroneou s ex am p le [5 ]:

[5 ] F rom [V andev oordeSolu ti ons ] , p rov i ng once and for all th at C + + p rom otes code reu s e.

template<typename1 T> struct S: typename2 X<T>::Base { S(): typename3 X<T>::Base(typename4 X<T>::Base(0)) {} typename5 X<T> f() { typename6 X<T>::C * p; // declaration of pointer p X<T>::D * q; // multiplication! } typename7 X<int>::C * s; }; struct U { typename8 X<int>::C * pc; };

E ach occu rrence of typename—correct or not—i s nu m bered wi th a s u bs cri p t for eas y reference. T h e fi rs t, typename1 , i ndi cates a tem p late p aram eter. T h e p rev i ou s ru les do not ap p ly to th i s fi rs t u s e. T h e s econd and th i rd typename s are di s allowed by th e th i rd i tem i n th e p rev i ou s ru les . N am es of bas e clas s es i n th es e two contex ts cannot be p receded by typename. H owev er, typename4 i s req u i red. H ere, th e nam e of th e bas e clas s i s not u s ed to denote wh at i s bei ng i ni ti ali z ed or deri v ed from . I ns tead, th e nam e i s p art of an ex p res s i on to cons tru ct a tem p orary X<T>::Base from i ts arg u m ent 0 (a s ort of conv ers i on, i f you wi ll). T h e fi fth typename i s p roh i bi ted becau s e th e nam e th at follows i t, X<T>, i s not a q u ali fi ed nam e. T h e s i x th occu rrence i s req u i red i f th i s s tatem ent i s to declare a p oi nter. T h e nex t li ne om i ts th e typename k eyword and i s , th erefore, i nterp reted by th e com p i ler as a m u lti p li cati on. T h e s ev enth typename i s op ti onal becau s e i t s ati s fi es all th e p rev i ou s ru les ex cep t th e las t. F i nally, typename8 i s p roh i bi ted becau s e i t i s not u s ed i ns i de a tem p late.

9.3.3 Dependent Names of Templates

A p roblem v ery s i m i lar to th e one encou ntered i n th e p rev i ou s s ecti on occu rs wh en a nam e of a tem p late i s dep endent. I n g eneral, a C + + com p i ler i s req u i red to treat a < followi ng th e nam e of a tem p late as th e beg i nni ng of a tem p late arg u m ent li s t; oth erwi s e, i t i s a " les s th an" op erator. A s i s th e cas e wi th typ e nam es , a com p i ler h as to as s u m e th at a dep endent nam e does not refer to a

Page 169: CPlusPlus Templates The Complete Guide

tem p late u nles s th e p rog ram m er p rov i des ex tra i nform ati on u s i ng th e k eyword template:

template<typename T> class Shell { public: template<int N> class In { public: template<int M> class Deep { public: virtual void f(); }; }; }; template<typename T, int N> class Weird { public: void case1(Shell<T>::template In<N>::template Deep<N>* p) { p->template Deep<N>::f(); // inhibit virtual call } void case2(Shell<T>::template In<T>::template Deep<T>& p) { p.template Deep<N>::f(); // inhibit virtual call } };

T h i s s om ewh at i ntri cate ex am p le s h ows h ow all th e op erators th at can q u ali fy a nam e (:: , -> , and .) m ay need to be followed by th e k eyword template. Sp eci fi cally, th i s i s th e cas e wh enev er th e typ e of th e nam e or ex p res s i on p recedi ng th e q u ali fyi ng op erator i s dep endent on a tem p late p aram eter, and th e nam e th at follows th e op erator i s a tem p late-i d (i n oth er words , a tem p late nam e followed by tem p late arg u m ents i n ang le brack ets ). F or ex am p le, i n th e ex p res s i on

p.template Deep<N>::f()

th e typ e of p dep ends on th e tem p late p aram eter T. C ons eq u ently, a C + + com p i ler cannot look u p Deep to s ee i f i t i s a tem p late, and we m u s t ex p li ci tly i ndi cate th at Deep i s th e nam e of a tem p late by i ns erti ng th e p refi x template. W i th ou t th i s p refi x , p.Deep<N>::f() i s p ars ed as ((p.Deep)<N)>f(). N ote als o th at th i s m ay need to h ap p en m u lti p le ti m es wi th i n a q u ali fi ed nam e becau s e q u ali fi ers th em s elv es m ay be q u ali fi ed wi th a dep endent q u ali fi er. (T h i s i s i llu s trated by th e declarati on of th e p aram eters of case1 and case2 i n th e p rev i ou s ex am p le.)

I f th e k eyword template i s om i tted i n cas es s u ch as th es e, th e op eni ng and clos i ng ang le brack ets are p ars ed as " les s th an" and " g reater th an" op erators .

[6 ]

Page 170: CPlusPlus Templates The Complete Guide

H owev er, i f th e k eyword i s not s tri ctly needed, i t i s i n fact not allowed at all. [6 ] Y ou cannot " j u s t s p ri nk le" tem p late q u ali fi ers th rou g h ou t you r code.

[6 ] T h i s i s actu ally not totally clear from th e tex t of th e s tandard, bu t th e p eop le wh o work ed on th at p art of th e tex t s eem to ag ree.

9.3.4 Dependent Names in Using-Declarations

U s i ng -declarati ons can bri ng i n nam es from two p laces : nam es p aces and clas s es . T h e nam es p ace cas e i s not relev ant i n th i s contex t becau s e th ere are no s u ch th i ng s as n amespac e templates. U s i ng -declarati ons th at bri ng i n nam es from clas s es can, i n fact, bri ng i n nam es only from a bas e clas s to a deri v ed clas s . Su ch u s i ng -declarati ons beh av e li k e " s ym boli c li nk s " or " s h ortcu ts " i n th e deri v ed clas s to th e bas e declarati on, th ereby allowi ng th e m em bers of th e deri v ed clas s to acces s th e nom i nated nam e as i f i t were actu ally a m em ber declared i n th at deri v ed clas s . A s h ort nontem p late ex am p le i llu s trates th e i dea better th an m ere words :

class BX { public: void f(int); void f(char const*); void g(); }; class DX : private BX { public: using BX::f; };

T h e p rev i ou s u s i ng -declarati on bri ng s i n th e nam e f of th e bas e clas s BX i nto th e deri v ed clas s DX. I n th i s cas e, th i s nam e i s as s oci ated wi th two di fferent declarati ons , th u s em p h as i z i ng th at we are deali ng wi th a m ech ani s m for nam es and not i ndi v i du al declarati ons of s u ch nam es . N ote als o th at th i s k i nd of u s i ng -declarati on can m ak e acces s i ble an oth erwi s e i nacces s i ble m em ber. T h e bas e BX (and th u s i ts m em bers ) are p ri v ate to th e clas s DX, ex cep t th at th e fu ncti ons BX::f h av e been i ntrodu ced i n th e p u bli c i nterface of DX and are th erefore av ai lable to th e cli ents of DX. B ecau s e u s i ng -declarati ons enable th i s , th e earli er m ech ani s m of ac c ess d ec lar ati on s i s d epr ec ated i n C + + (m eani ng th at fu tu re rev i s i ons of C + + m ay not contai n th e m ech ani s m ):

class DX : private BX { public: BX::f; // access declaration syntax is deprecated // use using BX::f instead };

B y now you can p robably p ercei v e th e p roblem wh en a u s i ng -declarati on bri ng s i n

Page 171: CPlusPlus Templates The Complete Guide

a nam e from a dep endent clas s . A lth ou g h we k now abou t th e nam e, we don' t k now wh eth er i t' s th e nam e of a typ e, a tem p late, or s om eth i ng els e:

template<typename T> class BXT { public: typedef T Mystery; template<typename U> struct Magic; }; template<typename T> class DXTT : private BXT<T> { public: using typename BXT<T>::Mystery; Mystery* p; // would be a syntax error if not for the typename };

A g ai n, i f we want a dep endent nam e to be brou g h t i n by a u s i ng -declarati on to denote a typ e, we m u s t ex p li ci tly s ay s o by i ns erti ng th e k eyword typename. Strang ely, th e C + + s tandard does not p rov i de for a s i m i lar m ech ani s m to m ark s u ch dep endent nam es as tem p lates . T h e followi ng s ni p p et i llu s trates th e p roblem :

template<typename T> class DXTM : private BXT<T> { public: using BXT<T>::template Magic; // ERROR: not standard Magic<T>* plink; // SYNTAX ERROR: Magic is not a }; // known template

M os t li k ely th i s i s an ov ers i g h t i n th e s tandard s p eci fi cati ons and fu tu re rev i s i ons wi ll p robably m ak e th e p rev i ou s cons tru ct v ali d.

9.3.5 ADL and Explicit Template Arguments

C ons i der th e followi ng ex am p le:

namespace N { class X { … }; template<int I> void select(X*); } void g (N::X* xp) { select<3>(xp); // ERROR: no ADL! }

I n th i s ex am p le, we m ay ex p ect th at th e tem p late select() i s fou nd th rou g h

Page 172: CPlusPlus Templates The Complete Guide

A D L i n th e call select<3>(xp). H owev er, th i s i s not th e cas e becau s e a com p i ler cannot deci de th at xp i s a fu ncti on call arg u m ent u nti l i t h as deci ded th at <3> i s a tem p late arg u m ent li s t. C onv ers ely, we cannot deci de th at <3> i s a tem p late arg u m ent li s t u nti l we h av e fou nd select() to be a tem p late. B ecau s e th i s ch i ck en and eg g p roblem cannot be res olv ed, th e ex p res s i on i s p ars ed as (select<3)>(xp), wh i ch m ak es no s ens e.

Page 173: CPlusPlus Templates The Complete Guide

9.4 Derivation and Class Templates

C las s tem p lates can i nh eri t or be i nh eri ted from . F or m any p u rp os es , th ere i s noth i ng s i g ni fi cantly di fferent between th e tem p late and nontem p late s cenari os . H owev er, th ere i s one i m p ortant s u btlety wh en deri v i ng a clas s tem p late from a bas e clas s referred to by a dep endent nam e. L et' s fi rs t look at th e s om ewh at s i m p ler cas e of nondep endent bas e clas s es .

9.4.1 Nondependent Base Classes

I n a clas s tem p late, a nondep endent bas e clas s i s one wi th a com p lete typ e th at can be determ i ned wi th ou t k nowi ng th e tem p late arg u m ents . I n oth er words , th e nam e of th i s bas e i s denoted u s i ng a nondep endent nam e. F or ex am p le:

template<typename X> class Base { public: int basefield; typedef int T; }; class D1: public Base<Base<void> > { // not a template case really public: void f() { basefield = 3; } // usual access to inherited member }; template<typename T> class D2 : public Base<double> { // nondependent base public: void f() { basefield = 7; } // usual access to inherited member T strange; // T is Base<double>::T, not the template parameter! };

N ondep endent bas es i n tem p lates beh av e v ery m u ch li k e bas es i n ordi nary nontem p late clas s es , bu t th ere i s a s li g h tly u nfortu nate s u rp ri s e: W h en an u nq u ali fi ed nam e i s look ed u p i n th e tem p lated deri v ati on, th e nondep endent bas es are cons i dered before th e li s t of tem p late p aram eters . T h i s m eans th at i n th e p rev i ou s ex am p le, th e m em ber strange of th e clas s tem p late D2 always h as th e typ e T corres p ondi ng to Base<double>::T (i n oth er words , int). F or ex am p le, th e followi ng fu ncti on i s not v ali d C + + (as s u m i ng th e p rev i ou s declarati ons ):

void g (D2<int*>& d2, int* p) {

Page 174: CPlusPlus Templates The Complete Guide

d2.strange = p; // ERROR: type mismatch! }

T h i s i s cou nteri ntu i ti v e and req u i res th e wri ter of th e deri v ed tem p late to be aware of nam es i n th e nondep endent bas es from wh i ch i t deri v es —ev en wh en th at deri v ati on i s i ndi rect or th e nam es are p ri v ate. I t wou ld p robably h av e been p referable to p lace tem p late p aram eters i n th e s cop e of th e enti ty th ey " tem p lati z e."

9.4.2 Dependent Base Classes

I n th e p rev i ou s ex am p le, th e bas e clas s i s fu lly determ i ned. I t does not dep end on a tem p late p aram eter. T h i s i m p li es th at a C + + com p i ler can look u p nondep endent nam es i n th os e bas e clas s es as s oon as th e tem p late defi ni ti on i s s een. A n alternati v e—not allowed by th e C + + s tandard—wou ld cons i s t i n delayi ng th e look u p of s u ch nam es u nti l th e tem p late i s i ns tanti ated. T h e di s adv antag e of th i s alternati v e ap p roach i s th at i t als o delays any error m es s ag es res u lti ng from m i s s i ng s ym bols u nti l i ns tanti ati on. H ence, th e C + + s tandard s p eci fi es th at a nondep endent nam e ap p eari ng i n a tem p late i s look ed u p as s oon as i t i s encou ntered. K eep i ng th i s i n m i nd, cons i der th e followi ng ex am p le:

template<typename T> class DD : public Base<T> { // dependent base public: void f() { basefield = 0; } // (1) problem… }; template<> // explicit specialization class Base<bool> { public: enum { basefield = 42 }; // (2) tricky! }; void g (DD<bool>& d) { d.f(); // (3) oops? }

A t p oi nt (1) we fi nd ou r reference to a nondep endent nam e basefield: I t m u s t be look ed u p ri g h t away. Su p p os e we look i t u p i n th e tem p late Base and bi nd i t to th e int m em ber th at we fi nd th erei n. H owev er, s h ortly after th i s we ov erri de th e g eneri c defi ni ti on of Base wi th an ex p li ci t s p eci ali z ati on. A s i t h ap p ens , th i s s p eci ali z ati on ch ang es th e m eani ng of th e basefield m em ber to wh i ch we already com m i tted! So, wh en we i ns tanti ate th e defi ni ti on of DD::f at p oi nt (3 ), we fi nd th at we too eag erly bou nd th e nondep endent nam e at p oi nt (1). T h ere i s no m odi fi able basefield i n DD<bool> th at was s p eci ali z ed at p oi nt (2), and an error m es s ag e s h ou ld h av e been i s s u ed.

Page 175: CPlusPlus Templates The Complete Guide

T o ci rcu m v ent th i s p roblem , s tandard C + + s ays th at nondep endent nam es are n ot look ed u p i n dep endent bas e clas s es [7 ] (bu t th ey are s ti ll look ed u p as s oon as th ey are encou ntered). So, a s tandard C + + com p i ler wi ll em i t a di ag nos ti c at p oi nt (1). T o correct th e code, i t s u ffi ces to m ak e th e nam e basefield dep endent becau s e dep endent nam es can be look ed u p only at th e ti m e of i ns tanti ati on, and at th at ti m e th e ex act bas e s p eci ali z ati on th at m u s t be ex p lored wi ll be k nown. F or ex am p le, at p oi nt (3 ), th e com p i ler wi ll k now th at th e bas e clas s of DD<bool> i s Base<bool> and th at th i s h as been ex p li ci tly s p eci ali z ed by th e p rog ram m er. I n th i s cas e, ou r p referred way to m ak e th e nam e dep endent i s as follows :

[7 ] T h i s i s p art of th e s o-called tw o-phase look u p ru les th at di s ti ng u i s h between a fi rs t p h as e wh en tem p late defi ni ti ons are fi rs t s een, and a s econd p h as e wh en tem p lates are i ns tanti ated (s ee Secti on 10.3 .1 on p ag e 14 6).

// Variation 1: template<typename T> class DD1 : public Base<T> { public: void f() { this->basefield = 0; } // lookup delayed };

A n alternati v e cons i s ts i n i ntrodu ci ng a dep endency u s i ng a q u ali fi ed nam e:

// Variation 2: template<typename T> class DD2 : public Base<T> { public: void f() { Base<T>::basefield = 0; } };

C are m u s t be tak en wi th th i s s olu ti on, becau s e i f th e u nq u ali fi ed nondep endent nam e i s u s ed to form a v i rtu al fu ncti on call, th en th e q u ali fi cati on i nh i bi ts th e v i rtu al call m ech ani s m and th e m eani ng of th e p rog ram ch ang es . N oneth eles s , th ere are s i tu ati ons wh en th e fi rs t v ari ati on cannot be u s ed and th i s alternati v e i s ap p rop ri ate:

template<typename T> class B { public: enumE{e1=6,e2=28,e3=496}; virtual void zero(E e = e1); virtual void one(E&); }; template<typename T> class D : public B<T> { public: void f() {

Page 176: CPlusPlus Templates The Complete Guide

typename D<T>::E e; // this->E would not be valid syntax this->zero(); // D<T>::zero() would inhibit virtuality one(e); // one is dependent because its argument } // is dependent };

N ote th at th e nam e one i n th e call one(e) i s dep endent on th e tem p late p aram eter s i m p ly becau s e th e typ e of one of th e call' s ex p li ci t arg u m ents i s dep endent. I m p li ci tly u s ed defau lt arg u m ents wi th a typ e th at dep ends on a tem p late p aram eter do not cou nt becau s e th e com p i ler cannot v eri fy th i s u nti l i t already h as deci ded th e look u p —a ch i ck en and eg g p roblem . T o av oi d s u btlety, we p refer to u s e th e this-> p refi x i n all s i tu ati ons th at allow i t—ev en for nontem p late code.

I f you fi nd th at th e rep eated q u ali fi cati ons are clu tteri ng u p you r code, you can bri ng a nam e from a dep endent bas e clas s i n th e deri v ed clas s once and for all:

// Variation 3: template<typename T> class DD3 : public Base<T> { public: using Base<T>::basefield; // (1) dependent name now in scope void f() { basefield = 0; } // (2) fine };

T h e look u p at p oi nt (2) s u cceeds and fi nds th e u si n g -d ec lar ati on of p oi nt (1). H owev er, th e u s i ng -declarati on i s not v eri fi ed u nti l i ns tanti ati on ti m e and ou r g oal i s ach i ev ed. T h ere are s om e s u btle li m i tati ons to th i s s ch em e. F or ex am p le, i f m u lti p le bas es are deri v ed from , th e p rog ram m er m u s t s elect ex actly wh i ch one contai ns th e des i red m em ber.

Page 177: CPlusPlus Templates The Complete Guide

9.5 Afternotes

T h e fi rs t com p i ler really to p ars e tem p late defi ni ti ons was dev elop ed by a com p any called T ali g ent i n th e m i d-19 9 0s . B efore th at—and ev en after th at—m os t com p i lers treated tem p lates as a s eq u ence of tok ens to be p layed back th rou g h th e p ars er at i ns tanti ati on ti m e. H ence no p ars i ng was done, ex cep t for a m i ni m al am ou nt s u ffi ci ent to fi nd th e end of a tem p late defi ni ti on. B i ll G i bbons was T ali g ent' s rep res entati v e to th e C + + com m i ttee and was th e p ri nci p al adv ocate for m ak i ng tem p lates u nam bi g u ou s ly p ars able. T h e T ali g ent effort was not releas ed u nti l th e com p i ler was acq u i red and com p leted by H ewlett-P ack ard (H P ), to becom e th e aC + + com p i ler. A m ong i ts com p eti ti v e adv antag es , th e aC + + com p i ler was q u i ck ly recog ni z ed for i ts h i g h q u ali ty di ag nos ti cs . T h e fact th at tem p late di ag nos ti cs were not always delayed u nti l i ns tanti ati on ti m e u ndou btedly contri bu ted to th i s p ercep ti on.

R elati v ely early du ri ng th e dev elop m ent of tem p lates , T om P ennello—a wi dely recog ni z ed p ars i ng ex p ert work i ng for M etaware—noted s om e of th e p roblem s as s oci ated wi th ang le brack ets . Strou s tru p als o com m ents on th at top i c i n [Strou s tru p D nE ] and arg u es th at h u m ans p refer to read ang le brack ets rath er th an p arenth es es . H owev er, oth er p os s i bi li ti es ex i s t, and P ennello s p eci fi cally p rop os ed braces (for ex am p le, List{::X } ) at a C + + s tandards m eeti ng i n 19 9 1 (h eld i n D allas ). [8] A t th at ti m e th e ex tent of th e p roblem was m ore li m i ted becau s e tem p lates nes ted i ns i de oth er tem p lates —s o-called memb er templates—were not v ali d and th u s th e di s cu s s i on of Secti on 9 .3 .3 on p ag e 13 2 was larg ely i rrelev ant. A s a res u lt, th e com m i ttee decli ned th e p rop os al to rep lace th e ang le brack ets .

[8] B races are not enti rely wi th ou t p roblem s ei th er. Sp eci fi cally, th e s yntax to s p eci ali z e clas s tem p lates wou ld req u i re nontri v i al adap tati on.

T h e nam e look u p ru le for nondep endent nam es and dep endent bas e clas s es th at i s des cri bed i n Secti on 9 .4 .2 on p ag e 13 6 was i ntrodu ced i n th e C + + s tandard i n 19 9 3 . I t was des cri bed to th e " g eneral p u bli c" i n B j arne Strou s tru p ' s [Strou s tru p D nE ] i n early 19 9 4 . Y et th e fi rs t g enerally av ai lable i m p lem entati on of th i s ru le di d not ap p ear u nti l early 19 9 7 wh en H P i ncorp orated i t i nto th ei r aC + + com p i ler, and by th en larg e am ou nts of code deri v ed clas s tem p lates from dep endent bas es . I ndeed, wh en th e H P eng i neers s tarted tes ti ng th ei r i m p lem entati on, th ey fou nd th at m os t of th e p rog ram s th at u s ed tem p lates i n nontri v i al ways no long er com p i led. [9 ] I n p arti cu lar, all i m p lem entati ons of th e S TL [10 ] brok e th e ru le i n m any h u ndreds —and s om eti m es th ou s ands —of p laces . T o eas e th e trans i ti on p roces s for th ei r cu s tom ers , H P s oftened th e di ag nos ti c

Page 178: CPlusPlus Templates The Complete Guide

as s oci ated wi th code th at as s u m ed th at nondep endent nam es cou ld be fou nd i n dep endent bas e clas s es as follows . W h en a nondep endent nam e u s ed i n th e s cop e of a clas s tem p late i s not fou nd u s i ng th e s tandard ru les , aC + + p eek s i ns i de th e dep endent bas es . I f th e nam e i s s ti ll not fou nd, a h ard error i s i s s u ed and com p i lati on fai ls . H owev er, i f th e nam e i s fou nd i n a dep endent bas e, a warni ng i s i s s u ed, and th e nam e i s m ark ed to be treated as i f i t were dep endent, s o th at look u p wi ll be reattem p ted at i ns tanti ati on ti m e.

[9 ] F ortu nately, th ey fou nd ou t before th ey releas ed th e new fu ncti onali ty. [10 ] I roni cally, th e fi rs t of th es e i m p lem entati ons h ad been dev elop ed by H P as well.

T h e look u p ru le th at cau s es a nam e i n nondep endent bas es to h i de an i denti cally nam ed tem p late p aram eter (Secti on 9 .4 .1 on p ag e 13 5 ) i s an ov ers i g h t, and i t i s not i m p os s i ble th at th i s wi ll be ch ang ed i n a rev i s i on of th e s tandard. I n any cas e, i t i s p robably wi s e to av oi d code wi th tem p late p aram eter nam es th at are als o u s ed i n nondep endent bas e clas s es .

A ndrew K oeni g fi rs t p rop os ed A D L for op erator fu ncti ons only (wh i ch i s wh y A D L i s s om eti m es called K oen i g look u p). T h e m oti v ati on was p ri m ari ly es th eti c: ex p li ci tly q u ali fyi ng op erator nam es wi th th ei r enclos i ng nam es p ace look s awk ward at bes t (for ex am p le, i ns tead of a+b we m ay need to wri te N::operator+(a, b)) and h av i ng to wri te u s i ng declarati ons for ev ery op erator can lead to u nwi eldy code. H ence, i t was deci ded th at op erators wou ld be look ed u p i n th e nam es p aces as s oci ated wi th arg u m ents . A D L was later ex tended to ordi nary fu ncti on nam es to accom m odate a li m i ted k i nd of fri end nam e i nj ecti on and to s u p p ort a two-p h as e look u p m odel for tem p lates and th ei r i ns tanti ati ons (C h ap ter 10). T h e g enerali z ed A D L ru les are als o called ex ten d ed K oen i g look u p.

Page 179: CPlusPlus Templates The Complete Guide

Chapter 10. Instantiation

T em p late i ns tanti ati on i s th e p roces s th at g enerates typ es and fu ncti ons from g eneri c tem p late defi ni ti ons . [1] T h e concep t of i ns tanti ati on of C + + tem p lates i s fu ndam ental bu t als o s om ewh at i ntri cate. O ne of th e u nderlyi ng reas ons for th i s i ntri cacy i s th at th e defi ni ti ons of enti ti es g enerated by a tem p late are no long er li m i ted to a s i ng le locati on i n th e s ou rce code. T h e locati on of th e tem p late, th e locati on wh ere th e tem p late i s u s ed, and th e locati ons wh ere th e tem p late arg u m ents are defi ned all p lay a role i n th e m eani ng of th e enti ty.

[1] T h e term i n stan ti ati on i s s om eti m es als o u s ed to refer to th e creati on of obj ects from typ es . I n th i s book , h owev er, i t always refers to template i ns tanti ati on.

I n th i s ch ap ter we ex p lai n h ow we can org ani z e ou r s ou rce code to enable p rop er tem p late u s e. I n addi ti on, we s u rv ey th e v ari ou s m eth ods th at are u s ed by th e m os t p op u lar C + + com p i lers to h andle tem p late i ns tanti ati on. A lth ou g h all th es e m eth ods s h ou ld be s em anti cally eq u i v alent, i t i s u s efu l to u nders tand bas i c p ri nci p les of you r com p i ler' s i ns tanti ati on s trateg y. E ach m ech ani s m com es wi th i ts s et of li ttle q u i rk s wh en bu i ldi ng real-li fe s oftware and, conv ers ely, each i nflu enced th e fi nal s p eci fi cati ons of s tandard C + + .

Page 180: CPlusPlus Templates The Complete Guide

10.1 On-Demand Instantiation

W h en a C + + com p i ler encou nters th e u s e of a tem p late s p eci ali z ati on, i t wi ll create th at s p eci ali z ati on by s u bs ti tu ti ng th e req u i red arg u m ents for th e tem p late p aram eters . [2] T h i s i s done au tom ati cally and req u i res no di recti on from th e cli ent code (or from th e tem p late defi ni ti on for th at m atter). T h i s on-dem and i ns tanti ati on featu re s ets C + + tem p lates ap art from s i m i lar faci li ti es i n oth er com p i led lang u ag es . I t i s s om eti m es als o called i mpli c i t or au tomati c i ns tanti ati on.

[2] T h e term spec i ali z ati on i s u s ed i n th e g eneral s ens e of an enti ty th at i s a s p eci fi c i ns tance of a tem p late (s ee C h ap ter 7 ). I t does not refer to th e ex pli c i t spec i ali z ati on m ech ani s m des cri bed i n C h ap ter 12.

O n-dem and i ns tanti ati on i m p li es th at th e com p i ler u s u ally needs acces s to th e fu ll defi ni ti on (i n oth er words , not j u s t th e declarati on) of th e tem p late and s om e of i ts m em bers at th e p oi nt of u s e. C ons i der th e followi ng ti ny s ou rce code fi le:

template<typename T> class C; // (1) declaration only C<int>* p = 0; // (2) fine: definition of C<int> not needed template<typename T> class C { public: void f(); // (3) member declaration }; // (4) class template definition completed void g (C<int>& c) // (5) use class template declaration only { c.f(); // (6) use class template definition; } // will need definition of C::f()

A t p oi nt (1) i n th e s ou rce code, only th e declarati on of th e tem p late i s av ai lable, not th e defi ni ti on (s u ch a declarati on i s s om eti m es called a f or w ar d d ec lar ati on ). A s i s th e cas e wi th ordi nary clas s es , you do not need th e defi ni ti on of a clas s tem p late to be i n s cop e to declare p oi nters or references to th i s typ e (as was done at p oi nt (2)). F or ex am p le, th e typ e of th e p aram eter of fu ncti on g does not req u i re th e fu ll defi ni ti on of th e tem p late C. H owev er, as s oon as a com p onent needs to k now th e s i z e of a tem p late s p eci ali z ati on or i f i t acces s es a m em ber of s u ch a s p eci ali z ati on, th e enti re clas s tem p late defi ni ti on i s req u i red to be i n s cop e. T h i s ex p lai ns wh y at p oi nt (6) i n th e s ou rce code, th e clas s tem p late

Page 181: CPlusPlus Templates The Complete Guide

defi ni ti on m u s t s een; oth erwi s e, th e com p i ler cannot v eri fy th at th e m em ber ex i s ts and i s acces s i ble (not p ri v ate or p rotected).

H ere i s anoth er ex p res s i on th at needs th e i ns tanti ati on of th e p rev i ou s clas s tem p late becau s e th e s i z e of C<void> i s needed:

C<void>* p = new C<void>;

I n th i s cas e, i ns tanti ati on i s needed s o th at th e com p i ler can determ i ne th e s i z e of C<void>.Y ou m i g h t obs erv e th at for th i s p arti cu lar tem p late, th e typ e of th e arg u m ent X s u bs ti tu ted for T wi ll not i nflu ence th e s i z e of th e tem p late becau s e i n any cas e, C<X> i s an em p ty clas s . H owev er, a com p i ler i s not req u i red to detect th i s . F u rth erm ore, i ns tanti ati on i s als o needed i n th i s ex am p le to determ i ne wh eth er C<void> h as an acces s i ble defau lt cons tru ctor and to ens u re C<void> does not declare p ri v ate op erators new or delete.

T h e need to acces s a m em ber of a clas s tem p late i s not always v ery ex p li ci tly v i s i ble i n th e s ou rce code. F or ex am p le, C + + ov erload res olu ti on req u i res v i s i bi li ty i nto clas s typ es for p aram eters of candi date fu ncti ons :

template<typename T> class C { public: C(int); // a constructor that can be called with a single parameter }; // may be used for implicit conversions void candidate(C<double> const&); // (1) void candidate(int) {} // (2) int main() { candidate(42); // both previous function declarations can be called }

T h e call candidate(42) wi ll res olv e to th e ov erloaded declarati on at p oi nt (2). H owev er, th e declarati on at p oi nt (1) cou ld als o be i ns tanti ated to ch eck wh eth er i t i s a v i able candi date for th e call (i t i s i n th i s cas e becau s e th e one-arg u m ent cons tru ctor can i m p li ci tly conv ert 42 to an rv alu e of typ e C<double>). N ote th at th e com p i ler i s allowed (bu t not req u i red) to p erform th i s i ns tanti ati on i f i t can res olv e th e call wi th ou t i t (as cou ld be th e cas e i n th i s ex am p le becau s e an i m p li ci t conv ers i on wou ld not be s elected ov er an ex act m atch ). N ote als o th at th e i ns tanti ati on of C<double> cou ld tri g g er an error, wh i ch m ay be s u rp ri s i ng .

Page 182: CPlusPlus Templates The Complete Guide
Page 183: CPlusPlus Templates The Complete Guide

10.2 Lazy Instantiation

T h e ex am p les s o far i llu s trate req u i rem ents th at are not fu ndam entally di fferent from th e req u i rem ents wh en u s i ng nontem p late clas s es . M any u s es req u i re a clas s typ e to be c omplete. F or th e tem p late cas e, th e com p i ler wi ll g enerate th i s com p lete defi ni ti on from th e clas s tem p late defi ni ti on.

A p erti nent q u es ti on now ari s es H ow m u ch of th e tem p late i s i ns tanti ated? A v ag u e ans wer i s th e followi ng : O nly as m u ch as i s really needed. I n oth er words , a com p i ler s h ou ld be " laz y" wh en i ns tanti ati ng tem p lates . L et' s look at ex actly wh at th i s laz i nes s entai ls .

W h en a clas s tem p late i s i m p li ci tly i ns tanti ated, each declarati on of i ts m em bers i s i ns tanti ated as well, bu t th e corres p ondi ng defi ni ti ons are not. T h ere are a few ex cep ti ons to th i s . F i rs t, i f th e clas s tem p late contai ns an anonym ou s u ni on, th e m em bers of th at u ni on' s defi ni ti on are als o i ns tanti ated. [3 ] T h e oth er ex cep ti on occu rs wi th v i rtu al m em ber fu ncti ons . T h ei r defi ni ti ons m ay or m ay not be i ns tanti ated as a res u lt of i ns tanti ati ng a clas s tem p late. M any i m p lem entati ons wi ll, i n fact, i ns tanti ate th e defi ni ti on becau s e th e i nternal s tru ctu re th at enables th e v i rtu al call m ech ani s m req u i res th e v i rtu al fu ncti ons actu ally to ex i s t as li nk able enti ti es .

[3 ] A nonym ou s u ni ons are always s p eci al i n th i s way: T h ei r m em bers can be cons i dered to be m em bers of th e enclos i ng clas s . A n anonym ou s u ni on i s p ri m ari ly a cons tru ct th at s ays th at s om e clas s m em bers s h are th e s am e s torag e.

D efau lt fu ncti on call arg u m ents are cons i dered s ep arately wh en i ns tanti ati ng tem p lates . Sp eci fi cally, th ey are not i ns tanti ated u nles s th ere i s a call to th at fu ncti on (or m em ber fu ncti on) th at actu ally m ak es u s e of th e defau lt arg u m ent. I f, on th e oth er h and, th at fu ncti on i s called wi th ex p li ci t arg u m ents th at ov erri de th e defau lt, th en th e defau lt arg u m ents are not i ns tanti ated.

L et' s p u t tog eth er an ex am p le th at i llu s trates all th es e i s s u es :

// details/lazy.cpp template <typename T> class Safe { }; template <int N> class Danger { public: typedef char Block[N]; // would fail for N<=0

Page 184: CPlusPlus Templates The Complete Guide

}; template <typename T, int N> class Tricky { public: virtual ~Tricky() { } void no_body_here(Safe<T> = 3); void inclass() { Danger<N> no_boom_yet; } // void error() { Danger<0> boom; } // void unsafe(T (*p)[N]); T operator->(); // virtual Safe<T> suspect(); struct Nested { Danger<N> pfew; }; union { // anonymous union int align; Safe<T> anonymous; }; }; int main() { Tricky<int, 0> ok; }

F i rs t cons i der th e p rev i ou s ex am p le wi th ou t th e fu ncti on main(). A s tandard C + + com p i ler norm ally com p i les th e tem p late defi ni ti ons to ch eck th e s yntax and g eneral s em anti c cons trai nts . I t wi ll, h owev er, " as s u m e th e bes t" wh en ch eck i ng cons trai nts i nv olv i ng tem p late p aram eters . F or ex am p le, th e p aram eter N i n th e m em ber typ edef for Block cou ld be z ero of neg ati v e (wh i ch wou ld be i nv ali d), bu t i t i s as s u m ed th at th i s i s n' t th e cas e. Si m i larly, th e defau lt arg u m ent s p eci fi cati on (= 3) on th e declarati on of th e m em ber no_body_here() i s s u s p i ci ou s becau s e th e tem p late Safe i s n' t i ni ti ali z able wi th an i nteg er, bu t th e as s u m p ti on i s th at th e defau lt arg u m ent won' t actu ally be needed for th e g eneri c defi ni ti on of Safe<T>. I f i t weren' t com m ented ou t, th e m em ber error() wou ld tri g g er an error wh i le th e tem p late i s com p i led becau s e th e u s e of Danger<0> req u i res a com p lete defi ni ti on of th e clas s Danger<0> , and g enerati ng th at clas s ru ns i nto an attem p t to typ edef an array wi th z ero elem ents ! T h i s i s th e cas e ev en th ou g h th e m em ber error() m ay not be u s ed and th erefore m ay not be i ns tanti ated. T h e error i s tri g g ered du ri ng th e p roces s i ng of th e g eneri c tem p late. T h e declarati on of th e m em ber unsafe(T (*p) [N]) , i n contras t, i s not a p roblem wh en N i s s ti ll an u ns u bs ti tu ted tem p late p aram eter.

N ow let' s analyz e wh at h ap p ens wh en we add th e fu ncti on main(). I t cau s es th e com p i ler to s u bs ti tu te int for T and 0 for N i n th e tem p late Tricky. N ot all th e m em ber defi ni ti ons wi ll be needed, bu t th e defau lt cons tru ctor (i m p li ci tly declared i n th i s cas e) and th e des tru ctor are defi ni tely called, and h ence th ei r defi ni ti ons

Page 185: CPlusPlus Templates The Complete Guide

m u s t be av ai lable s om eh ow (wh i ch i s th e cas e i n ou r ex am p le). I n p racti ce, th e defi ni ti ons of v i rtu al m em bers s h ou ld als o be p rov i ded; oth erwi s e, li nk er errors are li k ely to occu r. T h i s m ay h av e been a p roblem i f we h ad u ncom m ented th e declarati on of th e v i rtu al m em ber suspect() for wh i ch no defi ni ti on was p rov i ded. T h e defi ni ti ons of th e m em bers inclass() and struct Nested wou ld need th e com p lete typ e Danger<0> (wh i ch contai ns an i nv ali d typ edef as we di s cu s s ed earli er) bu t becau s e th es e defi ni ti ons are not u s ed, th ey are not g enerated, and no error i s tri g g ered. H owev er, all th e m em ber d ec lar ati on s are g enerated, and th es e cou ld contai n i nv ali d typ es as th e res u lt of ou r s u bs ti tu ti on. F or ex am p le, i f we u ncom m ented th e declarati on of unsafe(T (*p) [N]), we wou ld ag ai n create an array typ e wi th z ero elem ents , and th i s ti m e i t wou ld be an error. Si m i larly, h ad th e m em ber anonymous been declared wi th typ e Danger<N> i ns tead of Safe<T> , an error wou ld be tri g g ered becau s e typ e Danger<0> cannot be com p leted.

F i nally, we need to tak e note of operator->. N orm ally, th i s op erator m u s t retu rn a p oi nter typ e or anoth er clas s typ e to wh i ch operator-> ap p li es . T h i s s u g g es ts th at th e com p leti on of Tricky<int, 0> tri g g ers an error becau s e i t declares a retu rn typ e of int for operator->. H owev er, becau s e certai n natu ral clas s tem p late defi ni ti ons [4] tri g g er th es e k i nds of defi ni ti ons , th e lang u ag e ru le was m ade m ore flex i ble. A u s er-defi ned operator-> m u s t retu rn only a typ e to wh i ch anoth er (for ex am p le, bu i lti n) operator-> ap p li es i f th at op erator i s actu ally s elected by th e ov erload res olu ti on ru les . T h i s i s tru e ev en ou ts i de tem p lates (alth ou g h i t i s les s u s efu l i n th os e contex ts ). H ence, th e declarati on h ere tri g g ers no error, ev en th ou g h int i s s u bs i tu ted for th e retu rn typ e.

[4] T yp i cal ex am p les are s o-called smar t poi n ter tem p lates (for ex am p le, th e s tandard std::auto_ptr<T>). See als o C h ap ter 20.

Page 186: CPlusPlus Templates The Complete Guide

10.3 The C++ Instantiation Model

T em p late i ns tanti ati on i s th e p roces s of obtai ni ng a reg u lar clas s or fu ncti on from a corres p ondi ng tem p late enti ty by ap p rop ri ately s u bs ti tu ti ng th e tem p late p aram eters . T h i s m ay s ou nd fai rly s trai g h tforward, bu t i n p racti ce m any detai ls need to be form ally es tabli s h ed.

10.3.1 Two-Phase Lookup

I n C h ap ter 9 we s aw th at dep endent nam es cannot be res olv ed wh en p ars i ng tem p lates . I ns tead, th ey are look ed u p ag ai n at th e p oi nt of i ns tanti ati on. N ondep endent nam es , h owev er, are look ed u p early s o th at m any errors can be di ag nos ed wh en th e tem p late i s fi rs t s een. T h i s leads to th e concep t of tw o-phase look u p [5 ]: T h e fi rs t p h as e i s th e p ars i ng of a tem p late, and th e s econd p h as e i s i ts i ns tanti ati on.

[5 ] B es i de tw o-phase look u p , term s s u ch as tw o-stag e look u p or tw o-phase n ame look u p are als o u s ed.

D u ri ng th e fi rs t p h as e, nondep endent nam es are look ed u p wh i le th e tem p late i s bei ng p ars ed u s i ng both th e or d i n ar y look u p r u les and, i f ap p li cable, th e ru les for arg u m ent-dep endent look u p (A D L ). U nq u ali fi ed dep endent nam es (wh i ch are dep endent becau s e th ey look li k e th e nam e of a fu ncti on i n a fu ncti on call wi th dep endent arg u m ents ) are als o look ed u p th at way, bu t th e res u lt of th e look u p i s not cons i dered com p lete u nti l an addi ti onal look u p i s p erform ed wh en th e tem p late i s i ns tanti ated.

D u ri ng th e s econd p h as e, wh i ch occu rs wh en tem p lates are i ns tanti ated at a p oi nt called th e poi n t of i n stan ti ati on (P O I ), dep endent q u ali fi ed nam es are look ed u p (wi th th e tem p late p aram eters rep laced wi th th e tem p late arg u m ents for th at s p eci fi c i ns tanti ati on), and an addi ti onal A D L i s p erform ed for th e u nq u ali fi ed dep endent nam es .

10.3.2 Points of Instantiation

W e h av e already i llu s trated th at th ere are p oi nts i n th e s ou rce of tem p late cli ents wh ere a C + + com p i ler m u s t h av e acces s to th e declarati on or th e defi ni ti on of a tem p late enti ty. A poi n t of i n stan ti ati on (PO I ) i s created wh en a code cons tru ct refers to a tem p late s p eci ali z ati on i n s u ch a way th at th e defi ni ti on of th e corres p ondi ng tem p late needs to be i ns tanti ated to create th at s p eci ali z ati on. T h e P O I i s a p oi nt i n th e s ou rce wh ere th e s u bs ti tu ted tem p late cou ld be i ns erted. F or ex am p le:

Page 187: CPlusPlus Templates The Complete Guide

class MyInt { public: MyInt(int i); }; MyInt operator - (MyInt const&); bool operator > (MyInt const&, MyInt const&); typedef MyInt Int; template<typename T> void f(T i) { if (i>0) { g(-i); } } // (1) void g(Int) { // (2) f<Int>(42); // point of call // (3) } // (4)

W h en a C + + com p i ler s ees th e call f<Int>(42), i t k nows th e tem p late f wi ll need to be i ns tanti ated for T s u bs ti tu ted wi th MyInt: A P O I i s created. P oi nts (2) and (3 ) are v ery clos e to th e p oi nt of call, bu t th ey cannot be P O I s becau s e C + + does not allow u s to i ns ert th e defi ni ti on of ::f<Int>(Int) th ere. T h e es s enti al di fference between p oi nt (1) and p oi nt (4 ) i s th at at p oi nt (4 ) th e fu ncti on g(Int) i s v i s i ble, and h ence th e tem p late-dep endent call g(-i) can be res olv ed. H owev er, i f p oi nt (1) were th e P O I , th en th at call cou ld not be res olv ed becau s e g(Int) i s not yet v i s i ble. F ortu nately, C + + defi nes th e P O I for a reference to a nonclas s s p eci ali z ati on to be i m m edi ately after th e neares t nam es p ace s cop e declarati on or defi ni ti on th at contai ns th at reference. I n ou r ex am p le, th i s i s p oi nt (4 ).

Y ou m ay wonder wh y th i s ex am p le i nv olv ed th e typ e MyInt rath er th an s i m p le int. T h e ans wer li es i n th e fact th at th e s econd look u p p erform ed at th e P O I i s only an A D L . B ecau s e int h as no as s oci ated nam es p ace, th e P O I look u p wou ld th erefore not tak e p lace and wou ld not fi nd fu ncti on g. H ence, i f you were to rep lace th e typ edef for Int wi th

typedef int Int;

th e p rev i ou s ex am p le s h ou ld no long er com p i le. [6 ] [6 ] I n 2002 th e C + + s tandardi z ati on com m i ttee was s ti ll i nv es ti g ati ng alternati v es th at wou ld m ak e th e ex am p le v ali d wi th

Page 188: CPlusPlus Templates The Complete Guide

th e latter typ edef.

F or clas s s p eci ali z ati ons , th e s i tu ati on i s di fferent, as th e followi ng ex am p le i llu s trates :

template<typename T> class S { public: T m; }; // (5) unsigned long h() { // (6) return (unsigned long)sizeof(S<int>); // (7) } // (8)

A g ai n, th e fu ncti on s cop e p oi nts (6) and (7 ) cannot be P O I s becau s e a defi ni ti on of a nam es p ace s cop e clas s S<int> cannot ap p ear th ere (and tem p lates cannot ap p ear i n fu ncti on s cop e). I f we were to follow th e ru le for nonclas s i ns tances , th e P O I wou ld be at p oi nt (8 ), bu t th en th e ex p res s i on sizeof(S<int>) i s i nv ali d becau s e th e s i z e of S<int> cannot be determ i ned u nti l p oi nt (8 ) i s reach ed. T h erefore, th e P O I for a reference to a g enerated clas s i ns tance i s defi ned to be th e p oi nt i m m edi ately before th e neares t nam es p ace s cop e declarati on of defi ni ti on th at contai ns th e reference to th at i ns tance. I n ou r ex am p le, th i s i s p oi nt (5 ).

W h en a tem p late i s actu ally i ns tanti ated, th e need for addi ti onal i ns tanti ati ons m ay ap p ear. C ons i der a s h ort ex am p le:

template<typename T> class S { public: typedef int I; }; // (1) template<typename T> void f() { S<char>::I var1 = 41; typename S<T>::I var2 = 42; } int main() { f<double>(); } // (2): (2a), (2b)

Page 189: CPlusPlus Templates The Complete Guide

O u r p recedi ng di s cu s s i on already es tabli s h ed th at th e P O I for f<double> i s at p oi nt (2). T h e fu ncti on tem p late f() als o refers to th e clas s s p eci ali z ati on S<char> wi th a P O I th at i s th erefore at p oi nt (1). I t references S<T> too, bu t becau s e th i s i s s ti ll dep endent, we cannot really i ns tanti ate i t at th i s p oi nt. H owev er, i f we i ns tanti ate f<double> at p oi nt (2), we noti ce th at we als o need to i ns tanti ate th e defi ni ti on of S<double>. Su ch s econdary or trans i ti v e P O I s are defi ned s li g h tly di fferently. F or nonclas s enti ti es , th e s econdary P O I i s ex actly th e s am e as th e p ri m ary P O I . F or clas s enti ti es , th e s econdary P O I i m m edi ately p recedes (i n th e neares t enclos i ng nam es p ace s cop e) th e p ri m ary P O I . I n ou r ex am p le, th i s m eans th at th e P O I of f<double> can be p laced at p oi nt (2b), and j u s t before i t—at p oi nt (2a)—i s th e s econdary P O I for S<double>. N ote h ow th i s di ffers from th e P O I for S<char>.

A trans lati on u ni t u s u ally contai ns m u lti p le P O I s for th e s am e i ns tance. F or clas s tem p late i ns tances , only th e fi rs t P O I i n each trans lati on u ni t i s retai ned, and th e s u bs eq u ent ones are i g nored (th ey are not really cons i dered P O I s ). F or nonclas s i ns tances , all P O I s are retai ned. I n ei th er cas e, th e O D R req u i res th at th e i ns tanti ati ons occu rri ng at any of th e retai ned P O I s be eq u i v alent, bu t a C + + com p i ler does not need to v eri fy and di ag nos e v i olati ons of th i s ru le. T h i s allows a C + + com p i ler to p i ck j u s t one nonclas s P O I to p erform th e actu al i ns tanti ati on wi th ou t worryi ng th at anoth er P O I m i g h t res u lt i n a di fferent i ns tanti ati on.

I n p racti ce, m os t com p i lers delay th e actu al i ns tanti ati on of noni nli ne fu ncti on tem p lates to th e end of th e trans lati on u ni t. T h i s effecti v ely m ov es th e P O I s of th e corres p ondi ng tem p late s p eci ali z ati ons to th e end of th e trans lati on u ni t. T h e i ntenti on of th e C + + lang u ag e des i g ners was for th i s to be a v ali d i m p lem entati on tech ni q u e, bu t th e s tandard does not m ak e th i s clear.

10.3.3 The Inclusion and Separation Models

W h enev er a P O I i s encou ntered, th e defi ni ti on of th e corres p ondi ng tem p late m u s t s om eh ow be acces s i ble. F or clas s s p eci ali z ati ons th i s m eans th at th e clas s tem p late defi ni ti on m u s t h av e been s een earli er i n th e trans lati on u ni t. F or nonclas s P O I s th i s i s als o p os s i ble, and typ i cally nonclas s tem p late defi ni ti ons are s i m p ly added to h eader fi les th at are #included i nto th e trans lati on u ni t. T h i s s ou rce m odel for tem p late defi ni ti ons i s called th e i n c lu si on mod el , and at th e ti m e of th i s wri ti ng i t i s by far th e m os t p op u lar ap p roach .

F or nonclas s P O I s an alternati v e ex i s ts : T h e nonclas s tem p late can be declared u s i ng export and defi ned i n anoth er trans lati on u ni t. T h i s i s k nown as th e separ ati on mod el. T h e followi ng code ex cerp t i llu s trates th i s wi th ou r p erenni al max() tem p late:

Page 190: CPlusPlus Templates The Complete Guide

// Translation unit 1: #include <iostream> export template<typename T> T const& max (T const&, T const&); int main() { std::cout << max(7, 42) << std::endl; // (1) } // Translation unit 2: export template<typename T> T const& max (T const& a, T const& b) { return a<b?b:a; // (2) }

W h en com p i li ng th e fi rs t fi le, a com p i ler wi ll noti ce th e P O I for T s u bs ti tu ted wi th int created by th e s tatem ent at p oi nt (1). T h e com p i lati on s ys tem m u s t th en m ak e s u re th at th e defi ni ti on i n th e s econd fi le i s i ns tanti ated to s ati s fy th at P O I .

Looking Across Translation Units

Su p p os e th e fi rs t fi le j u s t s h own (trans lati on u ni t 1) i s rewri tten as follows :

// Translation unit 1: #include <iostream> export template<typename T> T const& max(T const&, T const&); namespace N { class I { public: I(int i): v(i) {} int v; }; bool operator < (I const& a, I const& b) { return a.v<b.v; } } int main() { std::cout << max(N::I(7), N::I(42)).v << std::endl; // (3) }

T h e P O I created at p oi nt (3 ) ag ai n req u i res th e defi ni ti on i n th e s econd fi le (trans lati on u ni t 2). H owev er, th i s defi ni ti on u s es th e < op erator wh i ch now refers to th e ov erloaded op erator declared i n trans lati on u ni t 1 and wh i ch i s not v i s i ble i n trans lati on u ni t 2. F or th i s to work , i t i s clear th at th e i ns tanti ati on p roces s needs to refer to two di fferent declarati on contex ts . [7 ] T h e fi rs t contex t i s th e one i n wh i ch th e tem p late i s defi ned, and th e s econd contex t i s th e one i n wh i ch typ e I i s declared. T o i nv olv e th es e two contex ts , nam es i n tem p lates are th erefore

Page 191: CPlusPlus Templates The Complete Guide

look ed u p i n two p h as es as ex p lai ned i n Secti on 10.3 .1 on p ag e 14 6. [7 ] A declarati on contex t i s th e collecti on of all declarati ons acces s i ble at a g i v en p oi nt.

T h e fi rs t p h as e occu rs wh en tem p lates are p ars ed (i n oth er words , wh en a C + + com p i ler fi rs t s ees th e tem p late defi ni ti on). A t th i s s tag e, nondep endent nam es are look ed u p u s i ng both th e ordi nary look u p ru les and th e A D L ru les . I n addi ti on, u nq u ali fi ed nam es of fu ncti ons th at are dep endent (becau s e th ei r arg u m ents are dep endent) are look ed u p u s i ng th e ordi nary look u p ru les , bu t th e res u lt i s m em ori z ed wi th ou t attem p ti ng ov erload res olu ti on—th i s i s done after th e s econd p h as e.

T h e s econd p h as e occu rs at th e p oi nt of i ns tanti ati on. A t th i s p oi nt, dep endent q u ali fi ed nam es are look ed u p u s i ng both ordi nary and arg u m ent-dep endent look u p ru les . D ep endent u nq u ali fi ed nam es (wh i ch were look ed u p u s i ng ordi nary look u p ru les du ri ng th e fi rs t p h as e) are now look ed u p u s i ng A D L ru les only, and th e res u lt of th e A D L i s th en com bi ned wi th th e res u lt of th e ordi nary look u p th at occu rred du ri ng th e fi rs t p h as e. I t i s th i s com bi ned s et th at i s u s ed to s elect th e called fu ncti on th rou g h ov erload res olu ti on.

A lth ou g h th i s two-p h as e look u p m ech ani s m s eem s es s enti al to enable th e s ep arati on m odel, i t i s als o th e m ech ani s m u s ed wi th th e i nclu s i on m odel. H owev er, m any early i m p lem entati ons of th e i nclu s i on m odel delayed all look u p s u nti l th e p oi nt of i ns tanti ati on. [8]

[8] T h i s res u lts i n a beh av i or th at i s clos e to wh at you ' d ex p ect from a m acro ex p ans i on m ech ani s m .

10.3.5 Examples

A few ex am p les i llu s trate m ore effecti v ely th e effect of wh at we j u s t des cri bed. O u r fi rs t ex am p le i s a s i m p le cas e of th e i nclu s i on m odel:

template<typename T> void f1(T x) { g1(x); // (1) } void g1(int) { } int main() { f1(7); // ERROR: g1 not found! } // (2) POI for f1<int>(int)

Page 192: CPlusPlus Templates The Complete Guide

T h e call f1(7) creates a p oi nt of i ns tanti ati on for f1<int>(int) j u s t ou ts i de of main() fu ncti on (at p oi nt (2)). I n th i s i ns tanti ati on, th e k ey i s s u e i s th e look u p of fu ncti on g1. W h en th e defi ni ti on of th e tem p late f1 i s fi rs t encou ntered, i t i s noted th at th e u nq u ali fi ed nam e g1 i s dep endent becau s e i t i s th e nam e of a fu ncti on i n a fu ncti on call wi th dep endent arg u m ents (th e typ e of th e arg u m ent x dep ends on th e tem p late p aram eter T). T h erefore, g1 i s look ed u p at p oi nt (1) u s i ng ordi nary look u p ru les ; h owev er, no g1 i s v i s i ble at th i s p oi nt. A t p oi nt (2), th e P O I , th e fu ncti on i s look ed u p ag ai n i n as s oci ated nam es p aces and clas s es , bu t th e only arg u m ent typ e i s int , and i t h as no as s oci ated nam es p aces and clas s es . T h erefore, g1 i s nev er fou nd ev en th ou g h ordi nary look u p at th e P O I wou ld h av e fou nd g1.

T h e s econd ex am p le dem ons trates h ow th e s ep arati on m odel can lead to ov erload am bi g u i ti es acros s trans lati on u ni ts . T h e ex am p le cons i s ts of th ree fi les (one of wh i ch i s a h eader fi le):

// File common.hpp: export template<typename T> void f(T); class A { }; class B { }; class X { public: operator A() { return A(); } operator B() { return B(); } }; // File a.cpp: #include "common.hpp" void g(A) { } int main() { f<X>(X()); } // File b.cpp: #include "common.hpp" void g(B) { } export template<typename T> void f(T x)

Page 193: CPlusPlus Templates The Complete Guide

{ g(x); }

T h e main() fu ncti on calls f<X>(X()) i n fi le a.cpp wh i ch res olv es to th e ex p orted tem p late defi ned i n fi le b.cpp. T h e call g(x) i s th erefore i ns tanti ated wi th an arg u m ent of typ e X. F u ncti on g() i s look ed u p twi ce: once u s i ng ordi nary look u p i n fi le b.cpp (wh en th e tem p late i s p ars ed) and once u s i ng A D L i n fi le a.cpp (wh ere th e tem p late i s i ns tanti ated). T h e fi rs t look u p fi nds g(B) , and th e s econd look u p fi nds g(A). B oth are v i able fu ncti ons th rou g h a u s er-defi ned conv ers i on, and h ence th e call i s really am bi g u ou s .

N ote th at i n fi le b.cpp th e call g(x) does not s eem am bi g u ou s at all. I t i s th e two-p h as e look u p m ech ani s m th at bri ng s i n p os s i bly u nex p ected candi date fu ncti ons . E x trem e care s h ou ld th erefore be tak en wh en wri ti ng and docu m enti ng ex p orted tem p lates .

Page 194: CPlusPlus Templates The Complete Guide

10.4 Implementation Schemes

I n th i s s ecti on we rev i ew s om e ways i n wh i ch p op u lar C + + i m p lem entati ons s u p p ort th e i nclu s i on m odel. A ll th es e i m p lem entati ons rely on two clas s i c com p onents : a c ompi ler and a li n k er . T h e com p i ler trans lates s ou rce code to obj ect fi les , wh i ch contai n m ach i ne code wi th s ym boli c annotati ons (cros s -referenci ng oth er obj ect fi les and li brari es ). T h e li nk er creates ex ecu table p rog ram s or li brari es by com bi ni ng th e obj ect fi les and res olv i ng th e s ym boli c cros s -references th ey contai n. I n wh at follows , we as s u m e s u ch a m odel ev en th ou g h i t i s enti rely p os s i ble (bu t not p op u lar) to i m p lem ent C + + i n oth er ways . F or ex am p le, you cou ld i m ag i ne a C + + i nterp reter.

W h en a clas s tem p late s p eci ali z ati on i s u s ed i n m u lti p le trans lati on u ni ts , a com p i ler wi ll rep eat th e i ns tanti ati on p roces s i n ev ery trans lati on u ni t. T h i s p os es v ery few p roblem s becau s e clas s defi ni ti ons do not di rectly create low-lev el code. T h ey are u s ed only i nternally by a C + + i m p lem entati on to v eri fy and i nterp ret v ari ou s oth er ex p res s i ons and declarati ons . I n th i s reg ard, th e m u lti p le i ns tanti ati ons of a clas s defi ni ti on are not m ateri ally di fferent from th e m u lti p le i nclu s i ons of a clas s defi ni ti on—typ i cally th rou g h h eader fi le i nclu s i on—i n v ari ou s trans lati on u ni ts .

H owev er, i f you i ns tanti ate a (noni nli ne) fu ncti on tem p late, th e s i tu ati on m ay be di fferent. I f you were to p rov i de m u lti p le defi ni ti ons of an ordi nary noni nli ne fu ncti on, you wou ld v i olate th e O D R . A s s u m e, for ex am p le, th at you com p i le and li nk a p rog ram cons i s ti ng of th e followi ng two fi les :

// File a.cpp: int main() { } // File b.cpp: int main() { }

C + + com p i lers wi ll com p i le each m odu le s ep arately wi th ou t any p roblem s becau s e i ndeed th ey are v ali d C + + trans lati on u ni ts . H owev er, you r li nk er wi ll m os t li k ely p rotes t i f you try to li nk th e two tog eth er. D u p li cate defi ni ti ons are not allowed.

I n contras t, cons i der th e tem p late cas e:

Page 195: CPlusPlus Templates The Complete Guide

// File t.hpp: // common header (inclusion model) template<typename T> class S { public: void f(); }; template<typename T> void S::f() // member definition { } void helper(S<int>*); // File a.cpp: #include "t.hpp" void helper(S<int>* s) { s->f(); // (1) first point of instantiation of S::f } // File b.cpp: #include "t.hpp" int main() { S<int> s; helper(&s); s.f(); // (2) second point of instantiation of S::f }

I f th e li nk er treats i ns tanti ated m em bers of tem p lates j u s t li k e i t does ordi nary fu ncti ons or m em ber fu ncti ons , th e com p i ler needs to ens u re th at i t g enerates code at only one of th e two P O I s : at p oi nts (1) or (2), bu t not both . T o ach i ev e th i s , a com p i ler h as to carry i nform ati on from one trans lati on u ni t to th e oth er, and th i s i s s om eth i ng C + + com p i lers were nev er req u i red to do p ri or to th e i ntrodu cti on of tem p lates . I n wh at follows , we di s cu s s th e th ree broad clas s es of s olu ti ons th at are en v og u e am ong C + + i m p lem enters .

N ote th at th e s am e p roblem occu rs wi th all li nk able enti ti es p rodu ced by tem p late i ns tanti ati on: i ns tanti ated fu ncti on tem p lates and m em ber fu ncti on tem p lates , as well as i ns tanti ated s tati c data m em bers .

10.4.1 Greedy Instantiation

T h e fi rs t C + + com p i lers th at p op u lari z ed g reedy i ns tanti ati on were p rodu ced by a com p any called B orland. I t h as g rown to be th e m os t com m only u s ed tech ni q u e am ong th e v ari ou s C + + s ys tem s , and i n p arti cu lar i t i s alm os t u ni v ers ally th e m ech ani s m of ch oi ce i n dev elop m ent env i ronm ents for M i cros oft W i ndows -bas ed p ers onal com p u ters .

G reedy i ns tanti ati on as s u m es th at th e li nk er i s aware th at certai n enti ti es —

Page 196: CPlusPlus Templates The Complete Guide

li nk able tem p late i ns tanti ati ons i n p arti cu lar—m ay i n fact ap p ear i n du p li cate acros s th e v ari ou s obj ect fi les and li brari es . T h e com p i ler wi ll typ i cally m ark th es e enti ti es i n a s p eci al way. W h en th e li nk er fi nds m u lti p le i ns tances , i t k eep s one and di s cards all th e oth ers . T h ere i s not m u ch m ore to i t th an th at.

I n th eory, g reedy i ns tanti ati on h as s om e s eri ou s drawback s :

• T h e com p i ler m ay be was ti ng ti m e on g enerati ng and op ti m i z i ng N i ns tanti ati ons , of wh i ch only one wi ll be k ep t.

• L i nk ers typ i cally do not ch eck th at two i ns tanti ati ons are i denti cal becau s e s om e i ns i g ni fi cant di fferences i n g enerated code can v ali dly occu r for m u lti p le i ns tances of one tem p late s p eci ali z ati on. T h es e s m all di fferences s h ou ld not cau s e th e li nk er to fai l. (T h es e di fferences cou ld res u lt from ti ny di fferences i n th e s tate of th e com p i ler at th e i ns tanti ati on ti m es .) H owev er, th i s often als o res u lts i n th e li nk er not noti ci ng m ore s u bs tanti al di fferences , s u ch as wh en one i ns tanti ati on was com p i led for m ax i m u m p erform ance wh ereas th e oth er was com p i led for m os t conv eni ent debu g g i ng .

• T h e s u m of all th e obj ect fi les cou ld p otenti ally be m u ch larg er th an wi th alternati v es becau s e th e s am e code m ay be du p li cated m any ti m es .

I n p racti ce, th es e s h ortcom i ng s do not s eem to h av e cau s ed m aj or p roblem s . P erh ap s th i s i s becau s e g reedy i ns tanti ati on contras ts v ery fav orably wi th th e alternati v es i n one i m p ortant as p ect: T h e tradi ti onal s ou rce-obj ect dep endency i s p res erv ed. I n p arti cu lar, one trans lati on u ni t g enerates bu t one obj ect fi le, and each obj ect fi le contai ns com p i led code for all th e li nk able defi ni ti ons i n th e corres p ondi ng s ou rce fi le (wh i ch i nclu des th e i ns tanti ated defi ni ti ons ).

F i nally, i t m ay be worth noti ng th at th e li nk er m ech ani s m th at allows du p li cate defi ni ti ons of li nk able enti ti es i s als o typ i cally u s ed to h andle du p li cate spi lled i n li n ed f u n c ti on s [9 ] and v i r tu al f u n c ti on d i spatc h tab les. [10 ] I f th i s m ech ani s m i s not av ai lable, th e alternati v e i s u s u ally to em i t th es e i tem s wi th i nternal li nk ag e, at th e ex p ens e of g enerati ng larg er code.

[9 ] W h en a com p i ler i s u nable to " i nli ne" ev ery call to a fu ncti on th at you m ark ed wi th th e k eyword inline , a s ep arate cop y of th e fu ncti on i s em i tted i n th e obj ect fi le. T h i s m ay h ap p en i n m u lti p le obj ect fi les . [10 ] V i rtu al fu ncti on calls are u s u ally i m p lem ented as i ndi rect calls th rou g h a table of p oi nters to fu ncti ons . See [L i p p m anO bj M od] for a th orou g h s tu dy of s u ch i m p lem entati on as p ects of C + + .

10.4.2 Queried Instantiation

T h e m os t p op u lar i m p lem entati on i n th i s categ ory i s p rov i ded by a com p any

Page 197: CPlusPlus Templates The Complete Guide

called S u n M i c r osy stems , s tarti ng wi th releas e 4 .0 of th ei r C + + com p i ler. Q u eri ed i ns tanti ati on i s concep tu ally rem ark ably s i m p le and eleg ant and yet i t i s ch ronolog i cally th e m os t recent clas s of i ns tanti ati on s ch em es th at we rev i ew h ere. I n th i s s ch em e, a databas e s h ared by th e com p i lati ons of all trans lati on u ni ts p arti ci p ati ng i n a p rog ram i s m ai ntai ned. T h i s databas e k eep s track of wh i ch s p eci ali z ati ons h av e been i ns tanti ated and on wh at s ou rce code th ey dep end. T h e g enerated s p eci ali z ati ons th em s elv es are typ i cally s tored wi th th i s i nform ati on i n th e databas e. W h enev er a p oi nt of i ns tanti ati on for a li nk able enti ty i s encou ntered, one of th ree th i ng s can h ap p en:

1. N o s p e c i a l i z a t i o n i s a v a i l a b l e : I n t h i s c a s e , i n s t a n t i a t i o n o c c u r s , a n d t h e r e s u l t i n g s p e c i a l i z a t i o n i s e n t e r e d i n t h e d a t a b a s e .

2 . A s p e c i a l i z a t i o n i s a v a i l a b l e b u t i s o u t o f d a t e b e c a u s e s o u r c e c h a n g e s h a v e o c c u r r e d s i n c e i t w a s g e n e r a t e d . H e r e , t o o , i n s t a n t i a t i o n o c c u r s , b u t t h e r e s u l t i n g s p e c i a l i z a t i o n r e p l a c e s t h e o n e p r e v i o u s l y s t o r e d i n t h e d a t a b a s e .

3 . A n u p -t o -d a t e s p e c i a l i z a t i o n i s a v a i l a b l e i n t h e d a t a b a s e . N o t h i n g n e e d s t o b e d o n e .

A lth ou g h concep tu ally s i m p le, th i s des i g n p res ents a few i m p lem entati on ch alleng es :

• I t i s not tri v i al to m ai ntai n correctly th e dep endenci es of th e databas e contents wi th res p ect to th e s tate of th e s ou rce code. A lth ou g h i t i s not i ncorrect to m i s tak e th e th i rd cas e for th e s econd, doi ng s o i ncreas es th e am ou nt of work done by th e com p i ler (and h ence ov erall bu i ld ti m e).

• I t i s q u i te com m on to com p i le m u lti p le s ou rce fi les concu rrently. H ence, an i ndu s tri al-s treng th i m p lem entati on needs to p rov i de th e ap p rop ri ate am ou nt of concu rrency control i n th e databas e.

D es p i te th es e ch alleng es , th e s ch em e can be i m p lem ented q u i te effi ci ently. F u rth erm ore, th ere are no obv i ou s p ath olog i cal cas es th at wou ld m ak e th i s s olu ti on s cale p oorly, i n contras t, for ex am p le, wi th g reedy i ns tanti ati on, wh i ch m ay lead to a lot of was ted work .

T h e u s e of a databas e m ay als o p res ent s om e p roblem s to th e p rog ram m er, u nfortu nately. T h e ori g i n of m os t of th es e p roblem s li es i n th at fact th at th e tradi ti onal com p i lati on m odel i nh eri ted from m os t C com p i lers no long er ap p li es : A s i ng le trans lati on u ni t no long er p rodu ces a s i ng le s tand-alone obj ect fi le. A s s u m e, for ex am p le, th at you wi s h to li nk you r fi nal p rog ram . T h i s li nk op erati on needs not only th e contents of each of th e obj ect fi les as s oci ated wi th you r v ari ou s trans lati on u ni ts , bu t als o th e obj ect fi les s tored i n th e databas e. Si m i larly, i f you create a bi nary li brary, you need to ens u re th at th e tool th at creates th at li brary—typ i cally a li nk er or an arch i v er—i s aware of th e contents of th e databas e. M ore g enerally, any tool th at op erates on obj ect fi les m ay need to be m ade aware of th e databas e contents . M any of th es e p roblem s can be allev i ated by not s tori ng th e i ns tanti ati ons i n th e databas e, bu t i ns tead by em i tti ng th e obj ect code i n th e obj ect fi le th at cau s ed th e i ns tanti ati on i n th e fi rs t

Page 198: CPlusPlus Templates The Complete Guide

p lace.

L i brari es p res ent yet anoth er ch alleng e. A nu m ber of g enerated s p eci ali z ati ons m ay be p ack ag ed i n a li brary. W h en th e li brary i s added to anoth er p roj ect, th at p roj ect' s databas e m ay need to be m ade aware of th e i ns tanti ati ons th at are already av ai lable. I f not, and i f th e p roj ect creates s om e of i ts own p oi nts of i ns tanti ati on for th e s p eci ali z ati ons p res ent i n th e li brary, du p li cate i ns tanti ati on m ay occu r. A p os s i ble s trateg y to deal wi th s u ch s i tu ati ons i s to u s e th e s am e li nk er tech nolog y th at enables g reedy i ns tanti ati on: M ak e th e li nk er aware of g enerated s p eci ali z ati ons and h av e i t weed ou t du p li cates (wh i ch s h ou ld noneth eles s occu r m u ch les s freq u ently th an wi th g reedy i ns tanti ati on). V ari ou s oth er s u btle arrang em ents of s ou rces , obj ect fi les , and li brari es can lead to fru s trati ng p roblem s s u ch as m i s s i ng i ns tanti ati ons becau s e th e obj ect code contai ni ng th e req u i red i ns tanti ati on was not li nk ed i n th e fi nal ex ecu table p rog ram . Su ch p roblem s s h ou ld not be cons tru ed as s h ortcom i ng s of th e q u eri ed i ns tanti ati on ap p roach bu t rath er s h ou ld be tak en as a s oli d arg u m ent ag ai ns t com p lex and s u btle s oftware bu i ld env i ronm ents .

10.4.3 Iterated Instantiation

T h e fi rs t com p i ler to s u p p ort C + + tem p lates was C front 3 .0—a di rect des cendant of th e com p i ler th at B j arne Strou s tru p wrote to dev elop th e lang u ag e. [11] A n i nflex i ble cons trai nt on C front was th at i t h ad to be v ery p ortable from p latform to p latform , and th i s m eant th at i t (1) u s ed th e C lang u ag e as a com m on targ et rep res entati on acros s all targ et p latform s and (b) u s ed th e local targ et li nk er. I n p arti cu lar, th i s i m p li ed th at th e li nk er was not aware of tem p lates . I n fact, C front em i tted tem p late i ns tanti ati ons as ordi nary C fu ncti ons , and th erefore i t h ad to av oi d du p li cate i ns tanti ati ons . A lth ou g h th e C front s ou rce m odel was di fferent from th e s tandard i nclu s i on and s ep arati on m odels , i ts i ns tanti ati on s trateg y can be adap ted to fi t th e i nclu s i on m odel. A s s u ch , i t als o m eri ts recog ni ti on as th e fi rs t i ncarnati on of i terated i ns tanti ati on. T h e C front i terati on can be des cri bed as follows :

[11] D o not let th i s p h ras e m i s lead you i nto th i nk i ng th at C front was an abs tract p rototyp e: I t was u s ed i n i ndu s tri al contex ts , and form ed th e bas i s of m any com m erci al C + + com p i ler offeri ng s . R eleas e 3 .0 ap p eared i n 19 9 1 bu t was p lag u ed wi th bu g s . V ers i on 3 .0.1 followed s oon th ereafter and m ade tem p lates u s able.

1. C o m p i l e t h e s o u r c e s w i t h o u t i n s t a n t i a t i n g a n y r e q u i r e d l i n k a b l e s p e c i a l i z a t i o n s . 2 . L i n k t h e o b j e c t f i l e s u s i n g a prelinker. 3 . Th e p r e l i n k e r i n v o k e s t h e l i n k e r a n d p a r s e s i t s e r r o r m e s s a g e s t o d e t e r m i n e w h e t h e r a n y a r e t h e

r e s u l t o f m i s s i n g i n s t a n t i a t i o n s . I f s o , t h e p r e l i n k e r i n v o k e s t h e c o m p i l e r o n s o u r c e s t h a t c o n t a i n t h e n e e d e d t e m p l a t e d e f i n i t i o n s , w i t h o p t i o n s t o g e n e r a t e t h e m i s s i n g i n s t a n t i a t i o n s .

4 . R e p e a t s t e p 3 i f a n y d e f i n i t i o n s a r e g e n e r a t e d .

T h e need to i terate s tep 3 i s p rom p ted by th e obs erv ati on th at th e i ns tanti ati on of

Page 199: CPlusPlus Templates The Complete Guide

one li nk able enti ty m ay lead to th e need for anoth er s u ch enti ty th at was not yet i ns tanti ated. E v entu ally th e i terati on wi ll " conv erg e, " and th e li nk er wi ll s u cceed i n bu i ldi ng a com p lete p rog ram .

T h e drawback s of th e ori g i nal C front s ch em e are q u i te s ev ere:

• T h e p ercei v ed ti m e to li nk i s au g m ented not only by th e p reli nk er ov erh ead bu t als o by th e cos t of ev ery req u i red recom p i lati on and reli nk i ng . Som e u s ers of C front-bas ed s ys tem s rep orted li nk ti m es of " a few days " com p ared wi th " abou t an h ou r" wi th th e alternati v e s ch em es rep orted earli er.

• D i ag nos ti cs (errors , warni ng s ) are delayed u nti l li nk ti m e. T h i s i s es p eci ally p ai nfu l wh en li nk i ng becom es ex p ens i v e and th e dev elop er m u s t wai t h ou rs j u s t to fi nd ou t abou t a typ o i n a tem p late defi ni ti on.

• Sp eci al care m u s t be tak en to rem em ber wh ere th e s ou rce contai ni ng a p arti cu lar defi ni ti on i s located (s tep 1). C front i n p arti cu lar u s ed a central rep os i tory, wh i ch h ad to deal wi th s om e of th e ch alleng es of th e central databas e i n th e q u eri ed i ns tanti ati on ap p roach . I n p arti cu lar, th e ori g i nal C front i m p lem entati on was not eng i neered to s u p p ort concu rrent com p i lati ons .

D es p i te th es e s h ortcom i ng s , th e i terati on p ri nci p le was refi ned for th e two com p i lati on s ys tem s th at wou ld later p i oneer th e m ore adv anced C + + tem p late featu res [12]: th e E di s on D es i g n G rou p ' s (E D G ) i m p lem entati on and H P ' s aC + + . [13 ] I n wh at follows , we ex p and on th e tech ni q u e dev elop ed by E D G to dem ons trate i ts C + + front-end tech nolog y. [14]

[12] W e are not u nbi as ed. H owev er, th e fi rs t p u bli cally av ai lable i m p lem entati ons of s u ch th i ng s as m em ber tem p lates , p arti al s p eci ali z ati on, m odern nam e look u p i n tem p lates , and th e tem p late s ep arati on m odel cam e ou t of th es e com p ani es . [13 ] H P ' s aC + + was g rown ou t of tech nolog y from a com p any called T ali g ent (later abs orbed by I nternati onal B u s i nes s M ach i nes , or I B M ). H P als o added g reedy i ns tanti ati on to aC + + and m ade th at th e defau lt m ech ani s m . [14] E D G does not s ell C + + i m p lem entati ons to end u s ers . I ns tead, th ey p rov i de an es s enti al bu t p ortable com p onent of s u ch an i m p lem entati on to oth er s oftware v endors wh o can th en i nteg rate th i s i nto a com p lete p latform -s p eci fi c s olu ti on. Som e of E D G ' s cu s tom ers ch oos e to k eep th ei r p ortable i ns tanti ati on i terati on, bu t th ey can j u s t as eas i ly adap t i t to a g reedy i ns tanti ati on env i ronm ent (wh i ch i s not p ortable becau s e i t dep ends on s p eci al li nk er cap abi li ti es ).

E D G ' s i terati on enables two-way com m u ni cati on between th e p reli nk er and th e v ari ou s com p i lati on s tep s : T h e p reli nk er can di rect i ns tanti ati ons p erform ed for a

Page 200: CPlusPlus Templates The Complete Guide

p arti cu lar trans lati on u ni t th rou g h an i n stan ti ati on r eq u est fi le, and th e com p i ler can noti fy th e p reli nk er abou t p os s i ble p oi nts of i ns tanti ati on ei th er by em beddi ng i nform ati on i n th e obj ect fi les or by p rodu ci ng s ep arate template i n f or mati on fi les . T h e i ns tanti ati on req u es t fi les and th e tem p late i nform ati on fi les h av e nam es th at corres p ond to th e nam e of th e fi le bei ng com p i led, bu t wi th s u ffi x es .ii and .ti res p ecti v ely. T h e i terati on work s as follows :

1. W h i l e c o m p i l i n g t h e s o u r c e o f a t r a n s l a t i o n u n i t , t h e E D G c o m p i l e r r e a d s t h e c o r r e s p o n d i n g .ii f i l e i f o n e e x i s t s a n d c r e a t e s t h e i n s t a n t i a t i o n s d i r e c t e d t h e r e i n . A t t h e s a m e t i m e , i t w r i t e s w h i c h p o i n t s o f i n s t a n t i a t i o n i t c o u l d h a v e h o n o r e d t o t h e o b j e c t f i l e r e s u l t i n g f r o m t h i s c o m p i l a t i o n o r t o a s e p a r a t e .ti f i l e . I t a l s o w r i t e s h o w t h i s f i l e i s c o m p i l e d .

2 . Th e l i n k s t e p i s i n t e r c e p t e d b y t h e p r e l i n k e r , w h i c h e x a m i n e s t h e o b j e c t f i l e s a n d c o r r e s p o n d i n g .ti f i l e s t h a t p a r t i c i p a t e i n t h e l i n k s t e p . F o r e a c h i n s t a n t i a t i o n t h a t h a s n o t y e t b e e n g e n e r a t e d , t h e r e q u i r e d d i r e c t i v e i s a d d e d t o a .ii f i l e c o r r e s p o n d i n g t o a t r a n s l a t i o n u n i t t h a t c a n h o n o r t h e d i r e c t i v e .

3 . I f a n y .ii f i l e s a r e m o d i f i e d , t h e p r e l i n k e r r e i n v o k e s t h e c o m p i l e r ( s t e p 1) f o r t h e c o r r e s p o n d i n g s o u r c e s f i l e s , a n d t h e p r e l i n k e r i t e r a t i o n r e p e a t s .

4 . W h e n c l o s u r e i s b e e n a c h i e v e d , a s i n g l e a c t u a l l i n k s t e p i s p e r f o r m e d .

T h i s s ch em e addres s es th e i s s u e of concu rrent bu i lds by m ai ntai ni ng g lobal i nform ati on on a p ertrans lati on-u ni t bas i s . T h e p ercei v ed li nk ti m e can s ti ll be s i g ni fi cantly h i g h er th an wi th g reedy and q u eri ed i ns tanti ati on, bu t becau s e no actu al li nk i ng i s p erform ed, th e g rowth i s m u ch les s catas trop h i c. M ore i m p ortant, becau s e th e p reli nk er m ai ntai ns g lobal cons i s tency am ong th e .ii fi les , th es e fi les can be reu s ed i n th e nex t bu i ld cycle. Sp eci fi cally, after h av i ng m ade s om e ch ang es to th e s ou rce, th e p rog ram m er res tarts a bu i ld of th e fi les affected by th e m odi fi cati ons . E ach res u lti ng com p i lati on i m m edi ately i ns tanti ates th e s p eci ali z ati ons req u es ted by th e .ii fi les th at li ng ered from th e p rev i ou s com p i lati on of th at fi le and ch ances are g ood th at th e p reli nk er wi ll not need to tri g g er addi ti onal recom p i les at li nk ti m e.

I n p racti ce, E D G ' s s ch em e work s q u i te well, and, alth ou g h a bu i ld " from s cratch " i s typ i cally m ore ti m e-cons u m i ng th an th e alternati v e s ch em es , s u bs eq u ent bu i ld ti m es are q u i te com p eti ti v e.

Page 201: CPlusPlus Templates The Complete Guide

10.5 Explicit Instantiation

I t i s p os s i ble to create ex p li ci tly a p oi nt of i ns tanti ati on for a tem p late s p eci ali z ati on. T h e cons tru ct th at ach i ev es th i s i s called an ex pli c i t i n stan ti ati on d i r ec ti v e. Syntacti cally, i t cons i s ts of th e k eyword template followed by a declarati on of th e s p eci ali z ati on to be i ns tanti ated. F or ex am p le:

template<typename T> void f(T) throw(T) { } // four valid explicit instantiations: template void f<int>(int) throw(int); template void f<>(float) throw(float); template void f(long) throw(long); template void f(char);

N ote th at ev ery i ns tanti ati on di recti v e i s v ali d. T em p late arg u m ents can be dedu ced (s ee C h ap ter 11), and ex cep ti on s p eci fi cati ons can be om i tted. I f th ey are not om i tted, th ey m u s t m atch th e one of th e tem p late.

M em bers of clas s tem p lates can als o be ex p li ci tly i ns tanti ated i n th i s way:

template<typename T> class S { public: void f() { } }; template void S<int>::f(); template class S<void>;

F u rth erm ore, all th e m em bers of a clas s tem p late s p eci ali z ati on can be ex p li ci tly i ns tanti ated by ex p li ci tly i ns tanti ati ng th e clas s tem p late s p eci ali z ati on.

M any early C + + com p i lati on s ys tem s di d not h av e au tom ati c i ns tanti ati on cap abi li ti es wh en th ey fi rs t i m p lem ented s u p p ort for tem p lates . I ns tead, s om e s ys tem s req u i red th at th e fu ncti on tem p late s p eci ali z ati ons u s ed by a p rog ram be m anu ally i ns tanti ated i n a s i ng le locati on. T h i s man u al i n stan ti ati on u s u ally i nv olv ed i m p lem entati on-s p eci fi c #pragma di recti v es .

T h e C + + s tandard th erefore codi fi ed th i s p racti ce by s p eci fyi ng a clean s yntax for i t. T h e s tandard als o s p eci fi es th at th ere can be at m os t one ex p li ci t i ns tanti ati on

Page 202: CPlusPlus Templates The Complete Guide

of a certai n tem p late s p eci ali z ati on i n a p rog ram . F u rth erm ore, i f a tem p late s p eci ali z ati on i s ex p li ci tly i ns tanti ated, i t s h ou ld not be ex p li ci tly s p eci ali z ed, and v i ce v ers a.

I n th e ori g i nal contex t of m anu al i ns tanti ati ons , th es e li m i tati ons m ay s eem h arm les s , bu t i n cu rrent p racti ce th ey cau s e s om e g ri ef.

F i rs t, cons i der a li brary i m p lem enter wh o releas es a fi rs t v ers i on of a fu ncti on tem p late:

// File toast.hpp: template<typename T> void toast(T const& x) { … }

C li ent code i s free to i nclu de th i s h eader and ex p li ci tly i ns tanti ate i ts tem p late:

// Client code: #include "toast.hpp" template void toast(float);

U nfortu nately, i f th e li brary wri ter deci des to s p eci ali z e toast<float> ex p li ci tly, th e cli ent code becom es i nv ali d. T h i s i s ev en m ore deli cate wh en th e li brary i s a s tandard li brary i m p lem ented by di fferent v endors . Som e m ay ex p li ci tly s p eci ali z e s om e s tandard tem p lates , wh ereas oth ers m ay not (or m ay s p eci ali z e di fferent s p eci ali z ati ons ). T h e cli ent code can th erefore not s p eci fy th e ex p li ci t i ns tanti ati on of li brary com p onents i n a p ortable m anner.

A t th e ti m e of th i s wri ti ng (2002), th e C + + s tandardi z ati on com m i ttee ap p ears i ncli ned to s tate th at i f an ex p li ci t i ns tanti ati on di recti v e follows an ex p li ci t s p eci ali z ati on for th e s am e enti ty, th en th e di recti v e i s wi th ou t effect. (T h e fi nal deci s i on i n th i s m atter i s s ti ll p endi ng and m ay not occu r i f i t ap p ears tech ni cally i nfeas i ble.)

A s econd ch alleng e wi th th e cu rrent li m i tati ons on ex p li ci t tem p late i ns tanti ati on s tem s from th ei r u s e as a m eans to i m p rov e com p i lati on ti m es . I ndeed, m any C + + p rog ram m ers h av e obs erv ed th at au tom ati c tem p late i ns tanti ati on h as a nontri v i al neg ati v e i m p act on bu i ld ti m es . A tech ni q u e to i m p rov e bu i ld ti m es cons i s ts i n m anu ally i ns tanti ati ng certai n tem p late s p eci ali z ati ons i n a s i ng le locati on and i nh i bi ti ng th e i ns tanti ati on i n all oth er trans lati on u ni ts . T h e only p ortable way to ens u re th i s i nh i bi ti on i s not to p rov i de th e tem p late defi ni ti on ex cep t i n th e trans lati on u ni t wh ere i t i s ex p li ci tly i ns tanti ated. F or ex am p le:

Page 203: CPlusPlus Templates The Complete Guide

// Translation unit 1: template<typename T> void f(); // no definition: prevents instantiation // in this translation unit void g() { f<int>(); } // Translation unit 2: template<typename T> void f() { } template void f<int>(); // manual instantiation void g(); int main() { g(); }

T h i s s olu ti on work s well, bu t i t req u i res control of th e s ou rce code th at p rov i des th e tem p late i nterface. O ften, th i s i s not th e cas e. T h e s ou rce code p rov i di ng th e tem p late cannot be m odi fi ed and always p rov i des th e defi ni ti on of th e tem p lates .

O ne " tri ck " th at i s s om eti m es u s ed i s to declare a tem p late as s p eci ali z ed i n all trans lati on u ni ts (wh i ch does i nh i bi t th e au tom ati c i ns tanti ati on of th at s p eci ali z ati on) ex cep t i n th e trans lati on u ni t i n wh i ch th at s p eci ali z ati on i s ex p li ci tly i ns tanti ated. T o i llu s trate th i s , let' s m odi fy ou r p rev i ou s ex am p le to i nclu de a defi ni ti on for th e tem p late:

// Translation unit 1: template<typename T> void f() { } template<> void f<int>(); // declared but not defined void g() { f<int>(); } // Translation unit 2: template<typename T> void f() { } template void f<int>(); // manual instantiation void g(); int main() {

Page 204: CPlusPlus Templates The Complete Guide

g(); }

U nfortu nately, th i s as s u m es th at th e obj ect code for a call to an ex p li ci tly s p eci ali z ed s p eci ali z ati on i s i denti cal to a call to th e m atch i ng g eneri c s p eci ali z ati on. T h i s as s u m p ti on i s not correct. Sev eral C + + com p i lers g enerate di fferent m ang led nam es for th e two enti ti es . [15 ] W i th th es e com p i lers , th e code does not li nk to a com p lete ex ecu table p rog ram .

[15 ] T h e m ang led nam e of a fu ncti on i s th e nam e s een by th e li nk er. I t com bi nes th e p lai n fu ncti on nam e wi th attri bu tes of i ts p aram eters , i ts tem p late arg u m ents , and s om eti m es s om e oth er p rop erti es to g enerate a u ni q u e nam e th at does not clas h wi th v ali dly ov erloaded fu ncti ons .

Som e com p i lers p rov i de an ex tens i on to i ndi cate th at a tem p late s p eci ali z ati on s h ou ld not be i ns tanti ated i n th at trans lati on u ni t. A p op u lar (bu t nons tandard) s yntax cons i s ts i n p rep endi ng th e k eyword extern before an ex p li ci t i ns tanti ati on di recti v e th at wou ld oth erwi s e tri g g er th e i ns tanti ati on. T h e fi rs t fi le i n ou r las t ex am p le can be rewri tten as follows for com p i lers s u p p orti ng th at ex tens i on:

// Translation unit 1: template<typename T> void f() { } extern template void f<int>(); // declared but not defined void g() { f<int>(); }

Page 205: CPlusPlus Templates The Complete Guide

10.6 Afternotes

T h i s ch ap ter deals wi th two related bu t di fferent i s s u es : th e C + + tem p late c ompi lati on mod els and v ari ou s C + + tem p late i n stan ti ati on mec han i sms.

T h e com p i lati on m odel determ i nes th e m eani ng of a tem p late at v ari ou s s tag es of th e trans lati on of a p rog ram . I n p arti cu lar, i t determ i nes wh at th e v ari ou s cons tru cts i n a tem p late m ean wh en i t i s i ns tanti ated. N am e look u p i s an es s enti al i ng redi ent of th e com p i lati on m odel of cou rs e. W h en we talk abou t th e i nclu s i on m odel and th e s ep arati on m odel, we talk abou t com p i lati on m odels . T h es e m odels are p art of th e lang u ag e defi ni ti on.

T h e i n stan ti ati on mec han i sms are th e ex ternal m ech ani s m s th at allow C + + i m p lem entati ons to create i ns tanti ati ons correctly. T h es e m ech ani s m s m ay be cons trai ned by req u i rem ents of th e li nk er and oth er s oftware bu i ldi ng tools .

H owev er, th e ori g i nal (C front) i m p lem entati on of tem p lates trans cended th es e two concep ts . I t created new trans lati on u ni ts for th e i ns tanti ati on of tem p lates u s i ng a p arti cu lar conv enti on for th e org ani z ati on of s ou rce fi les . T h e res u lti ng trans lati on u ni t was th en com p i led u s i ng wh at i s es s enti ally th e i nclu s i on m odel (alth ou g h th e C + + nam e look u p ru les were s u bs tanti ally di fferent back th en). So alth ou g h C front di d not i m p lem ent " s ep arate com p i lati on" of tem p lates , i t m anag ed to create an i llu s i on of s ep arate com p i lati on by creati ng i m p li ci t i nclu s i ons . V ari ou s later i m p lem entati ons p rov i ded a s om ewh at s i m i lar i m p li ci t i nclu s i on m ech ani s m by defau lt (Su n M i cros ys tem s ) or as an op ti on (H P , E D G ) to p rov i de s om e am ou nt of com p ati bi li ty wi th ex i s ti ng code dev elop ed for C front.

A n ex am p le i llu s trates th e detai ls of th e C front i m p lem entati on s ch em e:

// File template.hpp: template<class T> // Cfront doesn't know typename void f(T); // File template.cpp: template<class T> // Cfront doesn't know typename void f(T) { } // File app.hpp: class App { … }; // File main.cpp: #include "app.hpp"

Page 206: CPlusPlus Templates The Complete Guide

#include "template.hpp" int main() { App a; f(a); }

A t li nk ti m e, C front' s i terated i ns tanti ati on s ch em e th en creates a new trans lati on u ni t i nclu di ng fi les i t ex p ects to contai n th e i m p lem entati on of th e tem p lates i t fou nd i n h eader fi les . C front' s conv enti on for th i s i s to rep lace th e .h (or s i m i lar) s u ffi x of h eader fi les by .c (or one of a few oth er s u ffi x es li k e .C or .cpp). I n th i s cas e, th e g enerated trans lati on u ni t becom es

// File main.cpp: #include "template.hpp" #include "template.cpp" #include "app.hpp" static void _dummy_(App a1) { f(a1); }

T h i s trans lati on u ni t i s th en com p i led wi th a s p eci al op ti on to di s able th e code g enerati on of any enti ty defi ned i n an i nclu ded fi le. T h i s p rev ents th e i nclu s i on of template.cpp (wh i ch was p res u m ably already com p i led to anoth er obj ect fi le) from g enerati ng du p li cate defi ni ti ons of any li nk able enti ti es i t m ay contai n.

T h e fu ncti on _dummy_ i s u s ed to create references to th e s p eci ali z ati ons th at m u s t be i ns tanti ated. N ote als o th e reorderi ng of th e h eader fi les : C front actu ally i nclu des h eader analys i s code th at cau s es u nu s ed h eaders to be om i tted from th e g enerated trans lati on u ni t. U nfortu nately, th e tech ni q u e i s relati v ely bri ttle i n th e p res ence of m acros wi th s cop es th at cros s h eader bou ndari es .

I n contras t, th e s tandard C + + s ep arati on m odel i nv olv es th e s ep arate trans lati on of two (or m ore) trans lati on u ni ts , followed by an i ns tanti ati on th at h as acces s to th e enti ti es of both trans lati on u ni ts (p ri m ari ly enabled by A D L acros s trans lati on u ni ts ). B ecau s e i t i s not bas ed on i nclu s i on, i t does not i m p os e a p arti cu lar h eader fi le conv enti on, nor do m acro defi ni ti ons i n one trans lati on u ni t p ollu te th e oth er trans lati on u ni ts . H owev er, as we i llu s trated earli er i n th i s ch ap ter, m acros aren' t th e only way to create s u rp ri s es i n C + + , and th e ex p ort m odel i s ex p os ed to oth er form s of " p ollu ti on."

Page 207: CPlusPlus Templates The Complete Guide

Chapter 11. Template Argument Deduction

E x p li ci tly s p eci fyi ng tem p late arg u m ents on ev ery call to a fu ncti on tem p late (for ex am p le, concat<std::string, int>(s, 3)) can q u i ck ly lead to u nwi eldy code. F ortu nately, a C + + com p i ler can often au tom ati cally determ i ne th e i ntended tem p late arg u m ents u s i ng a p owerfu l p roces s called template ar g u men t d ed u c ti on .

I n th i s ch ap ter we ex p lai n th e detai ls of th e tem p late arg u m ent dedu cti on p roces s . A s i s often th e cas e i n C + + , th ere are m any ru les th at u s u ally p rodu ce an i ntu i ti v e res u lt. A s oli d u nders tandi ng of th i s ch ap ter allows u s to av oi d th e m ore s u rp ri s i ng s i tu ati ons .

Page 208: CPlusPlus Templates The Complete Guide

11.1 The Deduction Process

T h e dedu cti on p roces s com p ares th e typ es of an arg u m ent of a fu ncti on call wi th th e corres p ondi ng p aram eteri z ed typ e of a fu ncti on tem p late and attem p ts to conclu de th e correct s u bs ti tu ti on for one or m ore of th e dedu ced p aram eters . E ach arg u m ent-p aram eter p ai r i s analyz ed i ndep endently, and i f th e conclu s i ons di ffer i n th e end, th e dedu cti on p roces s fai ls . C ons i der th e followi ng ex am p le:

template<typename T> T const& max (T const& a, T const& b) { return a<b?b:a; } int g = max(1, 1.0);

H ere th e fi rs t call arg u m ent i s of typ e int s o th e p aram eter T of ou r ori g i nal max() tem p late i s tentati v ely dedu ced to be int. T h e s econd call arg u m ent i s a double, h owev er, and s o T s h ou ld be double for th i s arg u m ent: T h i s confli cts wi th th e p rev i ou s conclu s i on. N ote th at we s ay th at " th e dedu cti on p roces s fai ls , " not th at " th e p rog ram i s i nv ali d." A fter all, i t i s p os s i ble th at th e dedu cti on p roces s wou ld s u cceed for anoth er tem p late nam ed max (fu ncti on tem p lates can be ov erloaded m u ch li k e ordi nary fu ncti ons ; s ee Secti on 2.4 on p ag e 15 and C h ap ter 12).

I f all th e dedu ced tem p late p aram eters are cons i s tently determ i ned, th e dedu cti on p roces s can s ti ll fai l i f s u bs ti tu ti ng th e arg u m ents i n th e res t of th e fu ncti on declarati on res u lts i n an i nv ali d cons tru ct. F or ex am p le:

template<typename T> typename T::ElementT at (T const& a, int i) { return a[i]; } void f (int* p) { int x = at(p, 7); }

H ere T i s conclu ded to be int* (th ere i s only one p aram eter typ e wh ere T ap p ears , s o th ere are obv i ou s ly no analys i s confli cts ). H owev er, s u bs ti tu ti ng int* for T i n th e retu rn typ e T::ElementT i s clearly i nv ali d C + + , and th e dedu cti on p roces s fai ls . [1] T h e error m es s ag e i s li k ely to s ay th at no m atch was fou nd for

Page 209: CPlusPlus Templates The Complete Guide

th e call to at(). I n contras t, i f all th e tem p late arg u m ents are m enti oned ex p li ci tly, th en th ere i s no ch ance th at th e dedu cti on p roces s wi ll s u cceed for anoth er tem p late, and th e error m es s ag e i s m ore li k ely to s ay th at th e tem p late arg u m ents for at() are i nv ali d. Y ou can i nv es ti g ate th i s by com p ari ng th e di ag nos ti c for th e p rev i ou s ex am p le wi th

[1] I n th i s cas e, dedu cti on fai lu re leads to an error. H owev er, th i s falls u nder th e SF I N A E p ri nci p le (s ee Secti on 8 .3 .1 on p ag e 106): I f th ere were anoth er fu ncti on for wh i ch dedu cti on s u cceeds , th e code cou ld be v ali d.

void f (int* p) { int x = at<int*>(p, 7); }

on you r fav ori te C + + i m p lem entati on.

W e s ti ll need to ex p lore h ow arg u m ent-p aram eter m atch i ng p roceeds . W e des cri be i t i n term s of m atch i ng a typ e A (deri v ed from th e arg u m ent typ e) to a p aram eteri z ed typ e P (deri v ed from th e p aram eter declarati on). I f th e p aram eter i s declared wi th a reference declarator, P i s tak en to be th e typ e referenced, and A i s th e typ e of th e arg u m ent. O th erwi s e, h owev er, P i s th e declared p aram eter typ e, and A i s obtai ned from th e typ e of th e arg u m ent by d ec ay i n g [2] array and fu ncti on typ es to p oi nter typ es , i g nori ng top -lev el const and volatile q u ali fi ers . F or ex am p le:

[2] D ec ay i s th e term u s ed to refer to th e i m p li ci t conv ers i on of fu ncti on and array typ es to p oi nter typ es .

template<typename T> void f(T); //PisT template<typename T> void g(T&); // P is also T double x[20]; int const seven = 7; f(x); // nonreference parameter: T is double* g(x); // reference parameter: T is double[20] f(seven); // nonreference parameter: T is int g(seven); // reference parameter: T is int const f(7); // nonreference parameter: T is int g(7); // reference parameter: T is int => ERROR: can't pass 7 to int&

F or a call f(x), th e array typ e of x decays to typ e double*, wh i ch i s th e typ e dedu ced for T. I n f(seven) th e const q u ali fi cati on i s s tri p p ed and h ence T i s dedu ced to be int. I n contras t, calli ng g(x) dedu ces T to be typ e double[20]

Page 210: CPlusPlus Templates The Complete Guide

(no decay occu rs ). Si m i larly, g(seven) h as an lv alu e arg u m ent of typ e int const , and becau s e const and volatile q u ali fi ers are not drop p ed wh en m atch i ng reference p aram eters , T i s dedu ced to be int const. H owev er, note th at g(7) wou ld dedu ce T to be int (becau s e nonclas s rv alu e ex p res s i ons nev er h av e const or volatile q u ali fi ed typ es ), and th e call wou ld fai l becau s e an arg u m ent 7 cannot be p as s ed to a p aram eter of typ e int&.

T h e fact th at no decay occu rs for arg u m ents bou nd to reference p aram eters can be s u rp ri s i ng wh en th e arg u m ents are s tri ng li terals . R econs i der ou r max() tem p late:

template<typename T> T const& max(T const& a, T const& b);

I t wou ld be reas onable to ex p ect th at for th e ex p res s i on max("Apple", "Pear") T i s dedu ced to be char const*. H owev er, th e typ e of "Apple" i s char const[6] , and th e typ e of " P ear" i s char const[5]. N o array-to-p oi nter decay occu rs (becau s e th e dedu cti on i nv olv es reference p aram eters ), and th erefore T wou ld h av e to be both char[6] and char[5] for dedu cti on to s u cceed. T h at i s of cou rs e i m p os s i ble. See Secti on 5 .6 on p ag e 5 7 for addi ti onal di s cu s s i on on th i s top i c.

Page 211: CPlusPlus Templates The Complete Guide

11.2 Deduced Contexts

P aram eteri z ed typ es th at are cons i derably m ore com p lex th an T can be m atch ed to a g i v en arg u m ent

typ e. H ere are a few ex am p les th at are s ti ll fai rly bas i c:

template<typename T> void f1(T*); template<typename E, int N> void f2(E(&)[N]); template<typename T1, typename T2, typename T3> void f3(T1 (T2::*)(T3*)); class S { public: void f(double*); }; void g (int*** ppp) { bool b[42]; f1(ppp); // deduces T to be int** f2(b); // deduces E to be bool and N to be 42 f3(&S::f); // deduces T1 = void, T2=S, and T3 = double }

C om p lex typ e declarati ons are bu i lt from m ore elem entary cons tru cts (p oi nter, reference, array, and fu ncti on declarators ; p oi nter-to-m em ber declarators ; tem p late-i ds ; and s o forth ), and th e m atch i ng p roces s p roceeds from th e top -lev el cons tru ct and recu rs es th rou g h th e com p os i ng elem ents . I t i s fai r to s ay th at m os t typ e declarati on cons tru cts can be m atch ed i n th i s way, and th es e are called d ed u c ed c on tex ts. H owev er, a few cons tru cts are not dedu ced contex ts :

• Q u ali fi ed typ e nam es . A typ e nam e li k e Q<T>::X wi ll nev er be u s ed to dedu ce a tem p late p aram eter T, for ex am p le.

• N ontyp e ex p res s i ons th at are not j u s t a nontyp e p aram eter. A typ e nam e li k e S<I+1> wi ll nev er be u s ed to dedu ce I, for ex am p le. N ei th er wi ll T be dedu ced by m atch i ng ag ai ns t a p aram eter of typ e int(&)[sizeof(S<T>)].

T h es e li m i tati ons s h ou ld com e as no s u rp ri s e becau s e th e dedu cti on wou ld, i n g eneral, not be u ni q u e (or ev en fi ni te), alth ou g h q u ali fi ed typ e nam es are s om eti m es eas i ly ov erlook ed. A nondedu ced contex t does not au tom ati cally i m p ly th at th e p rog ram i s i n error or ev en th at th e p aram eter bei ng analyz ed cannot

Page 212: CPlusPlus Templates The Complete Guide

p arti ci p ate i n typ e dedu cti on. T o i llu s trate th i s , cons i der th e followi ng , m ore i ntri cate ex am p le:

// details/fppm.cpp template <int N> class X { public: typedef int I; void f(int) { } }; template<int N> void fppm(void (X<N>::*p)(X<N>::I)); int main() { fppm(&X<33>::f); // fine: N deduced to be 33 }

I n th e fu ncti on tem p late fppm() , th e s u bcons tru ct X<N>::I i s a nondedu ced contex t. H owev er, th e m em ber-clas s com p onent X<N> of th e p oi nter-to-m em ber typ e i s a dedu ci ble contex t, and wh en th e p aram eter N , wh i ch i s dedu ced from i t, i s p lu g g ed i n th e nondedu ced contex t, a typ e com p ati ble wi th th at of th e actu al arg u m ent &X<33>::f i s obtai ned. T h e dedu cti on th erefore s u cceeds on th at arg u m ent-p aram eter p ai r.

C onv ers ely, i t i s p os s i ble to dedu ce contradi cti ons for a p aram eter typ e enti rely bu i lt from dedu ced contex ts . F or ex am p le, as s u m i ng s u i tably declared clas s tem p lates X and Y:

template<typename T> void f(X<Y<T>, Y<T> >); void g() { f(X<Y<int>, Y<int> >()); // OK f(X<Y<int>, Y<char> >()); // ERROR: deduction fails }

T h e p roblem wi th th e s econd call to th e fu ncti on tem p late f() i s th at th e two arg u m ents dedu ce di fferent arg u m ents for th e p aram eter T, wh i ch i s not v ali d. (I n both cas es , th e fu ncti on call arg u m ent i s a tem p orary obj ect obtai ned by calli ng th e defau lt cons tru ctor of th e clas s tem p late X.)

Page 213: CPlusPlus Templates The Complete Guide

11.3 Special Deduction Situations

T h ere are two s i tu ati ons i n wh i ch th e p ai r (A , P) u s ed for dedu cti on i s not obtai ned from th e arg u m ents to a fu ncti on call and th e p aram eters of a fu ncti on tem p late. T h e fi rs t s i tu ati on occu rs wh en th e addres s of a fu ncti on tem p late i s tak en. I n th i s cas e, P i s th e p aram eteri z ed typ e of th e fu ncti on tem p late declarator, and A i s th e fu ncti on typ e u nderlyi ng th e p oi nter th at i s i ni ti ali z ed or as s i g ned to. F or ex am p le:

template<typename T> void f(T, T); void (*pf)(char, char) = &f;

I n th i s ex am p le, P i s void(T, T) and A i s void(char, char). D edu cti on s u cceeds wi th T s u bs ti tu ted wi th char, and pf i s i ni ti ali z ed to th e addres s of th e s p eci ali z ati on f<char>.

T h e oth er s p eci al s i tu ati on occu rs wi th conv ers i on op erator tem p lates . F or ex am p le:

class S { public: template<typename T, int N> operator T[N]&(); };

I n th i s cas e, th e p ai r (P , A) i s obtai ned as i f i t i nv olv ed an arg u m ent of th e typ e to wh i ch we are attem p ti ng to conv ert and a p aram eter typ e th at i s th e retu rn typ e of th e conv ers i on op erator. T h e followi ng code i llu s trates one v ari ati on:

void f(int (&)[20]); void g(S s) { f(s); }

H ere we are attem p ti ng to conv ert S to int (&)[20]. T yp e A i s th erefore int[20] and typ e P i s T[N]. T h e dedu cti on s u cceeds wi th T s u bs ti tu ted wi th int and N wi th 20.

Page 214: CPlusPlus Templates The Complete Guide
Page 215: CPlusPlus Templates The Complete Guide

11.4 Allowable Argument Conversions

N orm ally, tem p late dedu cti on attem p ts to fi nd a s u bs ti tu ti on of th e fu ncti on tem p late p aram eters th at m ak e th e p aram eteri z ed typ e P i denti cal to typ e A. H owev er, wh en th i s i s not p os s i ble, th e followi ng di fferences are tolerable:

• I f th e ori g i nal p aram eter was declared wi th a reference declarator, th e s u bs ti tu ted P typ e m ay be m ore const/volatile-q u ali fi ed th an th e A typ e.

• I f th e A typ e i s a p oi nter or p oi nter-to-m em ber typ e, i t m ay be conv erti ble to th e s u bs ti tu ted P typ e by a q u ali fi cati on conv ers i on (i n oth er words , a conv ers i on th at adds const and/or volatile q u ali fi ers ).

• U nles s dedu cti on occu rs for a conv ers i on op erator tem p late, th e s u bs ti tu ted P typ e m ay be a bas e clas s typ e of th e A typ e, or a p oi nter to a bas e clas s typ e of th e clas s typ e for wh i ch A i s a p oi nter typ e. F or ex am p le:

template<typename T> class B<T> { }; template<typename T> class D : B<T> { }; template<typename T> void f(B<T>*); void g(D<long> dl) { f(&dl); // deduction succeeds with T substituted with long }

T h e relax ed m atch i ng req u i rem ents are cons i dered only i f an ex act m atch was not p os s i ble. E v en s o, dedu cti on s u cceeds only i f ex actly one s u bs ti tu ti on was fou nd to fi t th e A typ e to th e s u bs ti tu ted P typ e wi th th es e added conv ers i ons .

Page 216: CPlusPlus Templates The Complete Guide

11.5 Class Template Parameters

T em p late arg u m ent dedu cti on ap p li es ex clu s i v ely to fu ncti on and m em ber fu ncti on tem p lates . I n p arti cu lar, th e arg u m ents for a clas s tem p late are not dedu ced from th e arg u m ents to a call of one of i ts cons tru ctors . F or ex am p le:

template<typename T> class S { public: S(T b) : a(b) { } private: T a; }; S x(12); // ERROR: the class template parameter T is not deduced // from the constructor call argument 12

Page 217: CPlusPlus Templates The Complete Guide

11.6 Default Call Arguments

D efau lt fu ncti on call arg u m ents can be s p eci fi ed i n fu ncti on tem p lates j u s t as th ey are i n ordi nary fu ncti ons :

template<typename T> void init (T* loc, T const& val = T()) { *loc = val; }

I n fact, as th i s ex am p le s h ows , th e defau lt fu ncti on call arg u m ent can dep end on a tem p late p aram eter. Su ch a dep endent defau lt arg u m ent i s i ns tanti ated only i f no ex p li ci t arg u m ent i s p rov i ded—a p ri nci p le th at m ak es th e followi ng ex am p le v ali d:

class S { public: S(int, int); }; S s(0, 0); int main() { init(&s, S(7, 42)); // T() is invalid for T=S, but the default // call argument T() needs no instantiation // because an explicit argument is given }

E v en wh en a defau lt call arg u m ent i s not dep endent, i t cannot be u s ed to dedu ce tem p late arg u m ents . T h i s m eans th at th e followi ng i s i nv ali d C + + :

template<typename T> void f (T x = 42) { } int main() { f<int>(); // OK: T = int f(); // ERROR: cannot deduce T from default call argument }

Page 218: CPlusPlus Templates The Complete Guide

11.7 The Barton-Nackman Trick

I n 19 9 4 , J oh n J . B arton and L ee R . N ack m an p res ented a tem p late tech ni q u e th at th ey called r estr i c ted template ex pan si on . T h e tech ni q u e was m oti v ated i n p art by th e fact th at—at th e ti m e— fu ncti on tem p lates cou ld not be ov erloaded [3 ] and nam es p aces were not av ai lable i n m os t com p i lers .

[3 ] I t m ay be worth wh i le to read Secti on 12.2 on p ag e 18 3 to u nders tand h ow fu ncti on tem p late ov erloadi ng work s i n m odern C + + .

T o i llu s trate th i s , s u p p os e we h av e a clas s tem p late Array for wh i ch we want to defi ne th e eq u ali ty op erator ==. O ne p os s i bi li ty i s to declare th e op erator as a m em ber of th e clas s tem p late, bu t th i s i s not g ood p racti ce becau s e th e fi rs t arg u m ent (bi ndi ng to th e this p oi nter) i s s u bj ect to conv ers i on ru les th at are di fferent from th e s econd arg u m ent. B ecau s e op erator == i s m eant to be s ym m etri cal wi th res p ect to i ts arg u m ents , i t i s p referable to declare i t as a nam es p ace s cop e fu ncti on. A n ou tli ne of a natu ral ap p roach to i ts i m p lem entati on m ay look li k e th e followi ng :

template<typename T> class Array { public: … }; template<typename T> bool operator == (Array<T> const& a, Array<T> const& b) { … }

H owev er, i f fu ncti on tem p lates cannot be ov erloaded, th i s p res ents a p roblem : N o oth er op erator == tem p late can be declared i n th at s cop e, and yet i t i s li k ely th at s u ch a tem p late wou ld be needed for oth er clas s tem p lates . B arton and N ack m an res olv ed th i s p roblem by defi ni ng th e op erator i n th e clas s as a norm al fri end fu ncti on:

template<typename T> class Array { public: … friend bool operator == (Array<T> const& a, Array<T> const& b) { return ArraysAreEqual(a, b); }

Page 219: CPlusPlus Templates The Complete Guide

};

Su p p os e th i s v ers i on of Array i s i ns tanti ated for typ e float. T h e fri end op erator fu ncti on i s th en declared as a res u lt of th at i ns tanti ati on, bu t note th at th i s fu ncti on i ts elf i s not an i ns tanti ati on of a fu ncti on tem p late. I t i s a norm al nontem p late fu ncti on th at g ets i n j ec ted i n th e g lobal s cop e as a s i de effect of th e i ns tanti ati on p roces s . B ecau s e i t i s a nontem p late fu ncti on, i t cou ld be ov erloaded wi th oth er declarati ons of op erator == ev en before ov erloadi ng of fu ncti on tem p lates was added to th e lang u ag e. B arton and N ack m an referred to th i s as r estr i c ted template ex pan si on becau s e i t av oi ded th e u s e of a tem p late operator==(T, T) th at ap p li ed to all typ es T (i n oth er words , u n res tri cted ex p ans i on).

B ecau s e operator == (Array<T> const&, Array<T> const&) i s defi ned i ns i de a clas s defi ni ti on, i t i s i m p li ci tly cons i dered to be an inline fu ncti on, and we th erefore deci ded to deleg ate th e i m p lem entati on to a fu ncti on tem p late ArraysAreEqual, wh i ch does n' t need to be inline and i s u nli k ely to confli ct wi th anoth er tem p late of th e s am e nam e.

T h e B arton-N ack m an tri ck i s no long er needed for i ts ori g i nal p u rp os e, bu t i t i s i nteres ti ng to s tu dy i t becau s e i t allows u s to g enerate nontem p late fu ncti ons along wi th clas s tem p late i ns tanti ati ons . B ecau s e th e fu ncti ons are not g enerated from fu ncti on tem p lates , th ey do not req u i re tem p late arg u m ent dedu cti on bu t are s u bj ect to norm al ov erload res olu ti on ru les (s ee A p p endi x B ). I n th eory, th i s cou ld m ean th at addi ti onal i m p li ci t conv ers i ons m ay be cons i dered wh en m atch i ng th e fri end fu ncti on to a s p eci fi c call s i te. H owev er, th i s i s of relati v ely li ttle benefi t becau s e i n s tandard C + + (u nli k e th e lang u ag e at th e ti m e B arton and N ack m an cam e u p wi th th ei r i dea), th e i nj ected fri end fu ncti on i s not u ncondi ti onally v i s i ble i n th e s u rrou ndi ng s cop e: I t i s v i s i ble only th rou g h A D L . T h i s m eans th at th e arg u m ents of th e fu ncti on call m u s t already h av e th e clas s contai ni ng th e fri end fu ncti on as an as s oci ated clas s . T h e fri end fu ncti on wou ld not be fou nd i f th e arg u m ents were of an u nrelated clas s typ e th at cou ld be conv erted to th e clas s contai ni ng th e fri end. F or ex am p le:

class S { }; template<typename T> class Wrapper { private: T object; public: Wrapper(T obj) : object(obj) { // implicit conversion from // T to Wrapper<T> } friend void f(Wrapper<T> const& a) { }

Page 220: CPlusPlus Templates The Complete Guide

}; int main() { Ss; Wrapper<S> w(s); f(w); // OK: Wrapper<S> is a class associated with w f(s); // ERROR: Wrapper<S> is not associated with s }

I n th i s ex am p le, th e call f(w) i s v ali d becau s e th e fu ncti on f() i s a fri end declared i n Wrapper<S> wh i ch i s a clas s as s oci ated wi th th e arg u m ent w. [4] H owev er, i n th e call f(s) th e fri end declarati on of fu ncti on f(Wrapper<S> const&) i s not v i s i ble becau s e th e clas s Wrapper<S> i n wh i ch i t i s defi ned i s not as s oci ated wi th th e arg u m ent s of typ e S. H ence, ev en th ou g h th ere i s a v ali d i m p li ci t conv ers i on from typ e S to typ e Wrapper<S> (th rou g h th e cons tru ctor of Wrapper<S>), th i s conv ers i on i s nev er cons i dered becau s e th e candi date fu ncti on f i s not fou nd i n th e fi rs t p lace.

[4] N ote th at S i s als o a clas s as s oci ated wi th w becau s e i t i s a tem p late arg u m ent for th e typ e of w.

I n conclu s i on, th ere i s li ttle adv antag e to defi ne a fri end fu ncti on i n a clas s tem p late ov er s i m p ly defi ni ng an ordi nary fu ncti on tem p late.

Page 221: CPlusPlus Templates The Complete Guide

11.8 Afternotes

T em p late arg u m ent dedu cti on for fu ncti on tem p lates was p art of th e ori g i nal C + + des i g n. I n fact, th e alternati v e p rov i ded by ex p li ci t tem p late arg u m ents di d not becom e p art of C + + u nti l m any years later.

F ri end nam e i nj ecti on was cons i dered h arm fu l by m any C + + lang u ag e ex p erts becau s e i t m ade th e v ali di ty of p rog ram s m ore s ens i ti v e to th e orderi ng of i ns tanti ati ons . B i ll G i bbons (wh o at th e ti m e was work i ng on th e T ali g ent com p i ler) was am ong th e m os t v ocal s u p p orters of addres s i ng th e p roblem , becau s e eli m i nati ng i ns tanti ati on order dep endenci es enabled new and i nteres ti ng C + + dev elop m ent env i ronm ents (on wh i ch T ali g ent was ru m ored to be work i ng ). H owev er, th e B arton-N ack m an tri ck req u i red a form of fri end nam e i nj ecti on, and i t i s th i s p arti cu lar tech ni q u e th at cau s ed i t to rem ai n i n th e lang u ag e i n i ts cu rrent (weak ened) form .

I nteres ti ng ly, m any p eop le h av e h eard of th e " B arton-N ack m an tri ck , " bu t few correctly as s oci ate i t wi th th e tech ni q u e des cri bed earli er. A s a res u lt, you m ay fi nd m any oth er tech ni q u es i nv olv i ng fri ends and tem p lates bei ng referred to i ncorrectly as th e " B arton-N ack m an tri ck " (for ex am p le, s ee Secti on 16.5 on p ag e 29 9 ).

Page 222: CPlusPlus Templates The Complete Guide

Chapter 12. Specialization and Overloading

So far we h av e s tu di ed h ow C + + tem p lates allow a g eneri c defi ni ti on to be ex p anded i nto a fam i ly of related clas s es or fu ncti ons . A lth ou g h th i s i s a p owerfu l m ech ani s m , th ere are m any s i tu ati ons i n wh i ch th e g eneri c form of an op erati on i s far from op ti m al for a s p eci fi c s u bs ti tu ti on of tem p late p aram eters .

C + + i s s om ewh at u ni q u e am ong oth er p op u lar p rog ram m i ng lang u ag es wi th s u p p ort for g eneri c p rog ram m i ng becau s e i t h as a ri ch s et of featu res th at enable th e trans p arent rep lacem ent of a g eneri c defi ni ti on by a m ore s p eci ali z ed faci li ty. I n th i s ch ap ter we s tu dy th e two C + + lang u ag e m ech ani s m s th at allow p rag m ati c dev i ati ons from p u re g eneri cnes s : tem p late s p eci ali z ati on and ov erloadi ng of fu ncti on tem p lates .

Page 223: CPlusPlus Templates The Complete Guide

12.1 When "Generic Code" Doesn't Quite Cut It

C ons i der th e followi ng ex am p le:

template<typename T> class Array { private: T* data; … public: Array(Array<T> const&); Array<T>& operator = (Array<T> const&); void exchange_with (Array<T>* b) { T* tmp = data; data = b->data; b->data = tmp; } T& operator[] (size_t k) { return data[k]; } … }; template<typename T> inline void exchange (T* a, T* b) { T tmp(*a); *a = *b; *b = tmp; }

F or s i m p le typ es , th e g eneri c i m p lem entati on of exchange() work s well. H owev er, for typ es wi th ex p ens i v e cop y op erati ons , th e g eneri c i m p lem entati on m ay be m u ch m ore ex p ens i v e—both i n term s of m ach i ne cycles and i n term s of m em ory u s ag e—th an an i m p lem entati on th at i s tai lored to th e p arti cu lar, g i v en s tru ctu re. I n ou r ex am p le, th e g eneri c i m p lem entati on req u i res one call to th e cop y cons tru ctor of Array<T> and two calls to i ts cop y-as s i g nm ent op erator. F or larg e data s tru ctu res th es e cop i es can often i nv olv e cop yi ng relati v ely larg e am ou nts of m em ory. H owev er, th e fu ncti onali ty of exchange() cou ld p res u m ably often be rep laced j u s t by s wap p i ng th e i nternal data p oi nters , as i s done i n th e m em ber fu ncti on exchange_with().

12.1.1 Transparent Customization

I n ou r p rev i ou s ex am p le, th e m em ber fu ncti on exchange_with() p rov i des an effi ci ent alternati v e to th e g eneri c exchange() fu ncti on, bu t th e need to u s e a

Page 224: CPlusPlus Templates The Complete Guide

di fferent fu ncti on i s i nconv eni ent i n s ev eral ways :

1. U s e r s o f t h e Array c l a s s h a v e t o r e m e m b e r a n e x t r a i n t e r f a c e a n d m u s t b e c a r e f u l t o u s e i t w h e n p o s s i b l e .

2 . G e n e r i c a l g o r i t h m s c a n g e n e r a l l y n o t d i s c r i m i n a t e b e t w e e n v a r i o u s p o s s i b i l i t i e s . F o r e x a m p l e : 3.

4. template<typename T>

5. void generic_algorithm(T* x, T* y)

6. {

7. …

8. exchange(x, y); // How do we select the right algorithm?

9. …

}

B ecau s e of th es e cons i derati ons , C + + tem p lates p rov i de ways to cu s tom i z e fu ncti on tem p lates and clas s tem p lates trans p arently. F or fu ncti on tem p lates , th i s i s ach i ev ed th rou g h th e ov erloadi ng m ech -ani s m . F or ex am p le, we can wri te an ov erloaded s et of quick_exchange() fu ncti on tem p lates as follows :

template<typename T> inline void quick_exchange(T* a, T* b) // (1) { T tmp(*a); *a = *b; *b = tmp; } template<typename T> inline void quick_exchange(Array<T>* a, Array<T>* b) // (2) { a->exchange_with(b); } void demo(Array<int>* p1, Array<int>* p2) { int x, y; quick_exchange(&x, &y); // uses (1) quick_exchange(p1, p2); // uses (2) }

T h e fi rs t call to quick_exchange() h as two arg u m ents of typ e int* and th erefore dedu cti on s u cceeds only wi th th e fi rs t tem p late (declared at p oi nt (1)) wh en T i s s u bs ti tu ted by int. T h ere i s th erefore no dou bt reg ardi ng wh i ch fu ncti on s h ou ld be called. I n contras t, th e s econd call can be m atch ed wi th ei th er tem p late: V i able fu ncti ons for th e call quick_exchange(p1, p2) are obtai ned both wh en s u bs ti tu ti ng Array<int> for T i n th e fi rs t tem p late and wh en s u bs ti tu ti ng int i n th e s econd tem p late. F u rth erm ore, both s u bs ti tu ti ons res u lt i n fu ncti ons wi th p aram eter typ es th at ex actly m atch th e arg u m ent typ es of th e s econd call. O rdi nari ly, th i s wou ld lead u s to conclu de th at th e call i s am bi g u ou s , bu t (as we wi ll di s cu s s later) th e C + + lang u ag e cons i ders th e s econd tem p late to be " m ore s p eci ali z ed" th an th e fi rs t. A ll oth er th i ng s bei ng eq u al, ov erload

Page 225: CPlusPlus Templates The Complete Guide

res olu ti on p refers th e m ore s p eci ali z ed tem p late and h ence s elects th e tem p late at p oi nt (2).

12.1.2 Semantic Transparency

T h e u s e of ov erloadi ng as s h own i n th e p rev i ou s s ecti on i s v ery u s efu l i n ach i ev i ng trans p arent cu s tom i z ati on of th e i ns tanti ati on p roces s , bu t i t i s i m p ortant to reali z e th at th i s " trans p arency" dep ends a g reat deal on th e detai ls of th e i m p lem entati on. T o i llu s trate th i s , cons i der ou r quick_exchange() s olu ti on. A lth ou g h both th e g eneri c alg ori th m and th e one cu s tom i z ed for Array<T> typ es end u p s wap p i ng th e v alu es th at are bei ng p oi nted to, th e s i de effects of th e op erati ons are v ery di fferent.

T h i s i s dram ati cally i llu s trated by cons i deri ng s om e code th at com p ares th e ex ch ang e of s tru ct obj ects wi th th e ex ch ang e of Array<T> s :

struct S { int x; } s1, s2; void distinguish (Array<int> a1, Array<int> a2) { int* p = &a1[0]; int* q = &s1.x; a1[0] = s1.x = 1; a2[0] = s2.x = 2; quick_exchange(&a1, &a2); // *p == 1 after this (still) quick_exchange(&s1, &s2); // *q == 2 after this }

T h i s ex am p le s h ows th at a p oi nter p i nto th e fi rs t Array becom es a p oi nter i nto th e s econd array after quick_exchange() i s called. H owev er, th e p oi nter i nto th e non-Array s1 rem ai ns p oi nti ng i nto s1 ev en after th e ex ch ang e op erati on: O nly th e v alu es th at were p oi nted to were ex ch ang ed. T h e di fference i s s i g ni fi cant enou g h th at i t m ay confu s e cli ents of th e tem p late i m p lem entati on. T h e p refi x quick_ i s h elp fu l i n attracti ng attenti on to th e fact th at a s h ortcu t m ay be tak en to reali z e th e des i red op erati on. H owev er, th e ori g i nal g eneri c exchange() tem p late can s ti ll h av e a u s efu l op ti m i z ati on for Array<T> s :

template<typename T> void exchange(Array<T>* a, Array<T>* b) { T* p = &a[0]; T* q = &b[0]; for (size_t k = a->size(); --k != 0; ) { exchange(p++, q++); } }

Page 226: CPlusPlus Templates The Complete Guide

T h e adv antag e of th i s v ers i on ov er th e g eneri c code i s th at no (p otenti ally) larg e tem p orary Array<T> i s needed. T h e exchange() tem p late i s called recu rs i v ely s o th at g ood p erform ance i s ach i ev ed ev en for typ es s u ch as Array<Array<char> >. N ote als o th at th e m ore s p eci ali z ed v ers i on of th e tem p late i s not declared i nli ne becau s e i t does a cons i derable am ou nt of work of i ts own, wh ereas th e ori g i nal g eneri c i m p lem entati on i s i nli ne becau s e i t p erform s only a few op erati ons (each of wh i ch i s p otenti ally ex p ens i v e).

Page 227: CPlusPlus Templates The Complete Guide

12.2 Overloading Function Templates

I n th e p rev i ou s s ecti on we s aw th at two fu ncti on tem p lates wi th th e s am e nam e can coex i s t, ev en th ou g h th ey m ay be i ns tanti ated s o th at both h av e i denti cal p aram eter typ es . H ere i s anoth er s i m p le ex am p le of th i s :

// details/funcoverload.hpp template<typename T> int f(T) { return 1; } template<typename T> int f(T*) { return 2; }

W h en T i s s u bs ti tu ted by int* i n th e fi rs t tem p late, a fu ncti on i s obtai ned th at h as ex actly th e s am e p aram eter (and retu rn) typ es as th e one obtai ned by s u bs ti tu ti ng int for T i n th e s econd tem p late. N ot only can th es e tem p lates coex i s t, th ei r res p ecti v e i ns tanti ati ons can coex i s t ev en i f th ey h av e i denti cal p aram eter and retu rn typ es .

T h e followi ng dem ons trates h ow two s u ch g enerated fu ncti ons can be called u s i ng ex p li ci t tem p late arg u m ent s yntax (as s u m i ng th e p rev i ou s tem p late declarati ons ):

// details/funcoverload.cpp #include <iostream> #include "funcoverload.hpp" int main() { std::cout << f<int*>((int*)0) << std::endl; std::cout << f<int>((int*)0) << std::endl; }

T h i s p rog ram h as th e followi ng ou tp u t:

1 2

T o clari fy th i s , let' s analyz e th e call f<int*>((int*)0) i n detai l. [1] T h e s yntax

Page 228: CPlusPlus Templates The Complete Guide

f<int*> i ndi cates th at we want to s u bs ti tu te th e fi rs t tem p late p aram eter of th e tem p late f wi th int* wi th ou t relyi ng on tem p late arg u m ent dedu cti on. I n th i s cas e th ere i s m ore th an one tem p late f, and th erefore an ov erload s et i s created contai ni ng two fu ncti ons g enerated from tem p lates : f<int*>(int*) (g enerated from th e fi rs t tem p late) and f<int*>(int**) (g enerated from th e s econd tem p late). T h e arg u m ent to th e call (int*)0 h as typ e int*. T h i s m atch es only th e fu ncti on g enerated from th e fi rs t tem p late, and h ence th at i s th e fu ncti on th at ends u p bei ng called.

[1] N ote th at th e ex p res s i on 0 i s an i nteg er and not a nu ll p oi nter cons tant. I t becom es a nu ll p oi nter cons tant after a s p eci al i m p li ci t conv ers i on, bu t th i s conv ers i on i s not cons i dered du ri ng tem p late arg u m ent dedu cti on.

A s i m i lar analys i s can be wri tten for th e s econd call.

12.2.1 Signatures

T wo fu ncti ons can coex i s t i n a p rog ram i f th ey h av e di s ti nct s i g natu res . W e defi ne th e s i g natu re of a fu ncti on as th e followi ng i nform ati on [2]:

[2] T h i s defi ni ti on i s di fferent from th at g i v en i n th e C + + s tandard, bu t i ts cons eq u ences are eq u i v alent.

1. Th e u n q u a l i f i e d n a m e o f t h e f u n c t i o n ( o r t h e n a m e o f t h e f u n c t i o n t e m p l a t e f r o m w h i c h i t w a s g e n e r a t e d )

2 . Th e c l a s s o r n a m e s p a c e s c o p e o f t h a t n a m e a n d , i f t h e n a m e h a s i n t e r n a l l i n k a g e , t h e t r a n s l a t i o n u n i t i n w h i c h t h e n a m e i s d e c l a r e d

3 . Th e const , volatile , o r const volatile q u a l i f i c a t i o n o f t h e f u n c t i o n ( i f i t i s a m e m b e r f u n c t i o n w i t h s u c h a q u a l i f i e r )

4 . Th e t y p e s o f t h e f u n c t i o n p a r a m e t e r s ( b e f o r e t e m p l a t e p a r a m e t e r s a r e s u b s t i t u t e d i f t h e f u n c t i o n i s g e n e r a t e d f r o m a f u n c t i o n t e m p l a t e )

5 . I t s r e t u r n t y p e , i f t h e f u n c t i o n i s g e n e r a t e d f r o m a f u n c t i o n t e m p l a t e 6 . Th e t e m p l a t e p a r a m e t e r s a n d t h e t e m p l a t e a r g u m e n t s , i f t h e f u n c t i o n i s g e n e r a t e d f r o m a f u n c t i o n

t e m p l a t e

T h i s m eans th at th e followi ng tem p lates and th ei r i ns tanti ati ons cou ld, i n p ri nci p le, coex i s t i n th e s am e p rog ram :

template<typename T1, typename T2> void f1(T1, T2); template<typename T1, typename T2> void f1(T2, T1); template<typename T> long f2(T); template<typename T> char f2(T);

Page 229: CPlusPlus Templates The Complete Guide

H owev er, th ey cannot always be u s ed wh en th ey' re declared i n th e s am e s cop e becau s e i ns tanti ati ng both creates an ov erload am bi g u i ty. F or ex am p le:

#include <iostream> template<typename T1, typename T2> void f1(T1, T2) { std::cout << "f1(T1, T2)\n"; } template<typename T1, typename T2> void f1(T2, T1) { std::cout << "f1(T2, T1)\n"; } // fine so far int main() { f1<char, char>('a', 'b'); // ERROR: ambiguous }

H ere, th e fu ncti on f1<T1 = char, T2 = char>(T1, T2) can coex i s t wi th th e fu ncti on f1<T1 = char, T2 = char>(T2, T1), bu t ov erload res olu ti on wi ll nev er p refer one ov er th e oth er. I f th e tem p lates ap p ear i n di fferent trans lati on u ni ts , th en th e two i ns tanti ati ons can actu ally ex i s t i n th e s am e p rog ram (and, for ex am p le, a li nk er s h ou ld not com p lai n abou t du p li cate defi ni ti ons becau s e th e s i g natu res of th e i ns tanti ati ons are di s ti nct):

// Translation unit 1: #include <iostream> template<typename T1, typename T2> void f1(T1, T2) { std::cout << "f1(T1, T2)\n"; } void g() { f1<char, char>('a', 'b'); } // Translation unit 2: #include <iostream> template<typename T1, typename T2> void f1(T2, T1) { std::cout << "f1(T2, T1)\n"; }

Page 230: CPlusPlus Templates The Complete Guide

extern void g(); // defined in translation unit 1 int main() { f1<char, char>('a', 'b'); g(); }

T h i s p rog ram i s v ali d and p rodu ces th e followi ng ou tp u t:

f1(T2, T1) f1(T1, T2)

12.2.2 Partial Ordering of Overloaded Function Templates

R econs i der ou r earli er ex am p le:

#include <iostream> template<typename T> int f(T) { return 1; } template<typename T> int f(T*) { return 2; } int main() { std::cout << f<int*>((int*)0) << std::endl; std::cout << f<int>((int*)0) << std::endl; }

W e fou nd th at after s u bs ti tu ti ng th e g i v en tem p late arg u m ent li s ts (<int*> and <int>), ov erload res olu ti on ended u p s electi ng th e ri g h t fu ncti on to call. H owev er, a fu ncti on i s s elected ev en wh en ex p li ci t tem p late arg u m ents are not p rov i ded. I n th i s cas e, tem p late arg u m ent dedu cti on com es i nto p lay. L et' s s li g h tly m odi fy fu ncti on main() i n th e p rev i ou s ex am p le to di s cu s s th i s m ech ani s m :

#include <iostream> template<typename T> int f(T) { return 1; } template<typename T> int f(T*)

Page 231: CPlusPlus Templates The Complete Guide

{ return 2; } int main() { std::cout << f(0) << std::endl; std::cout << f((int*)0) << std::endl; }

C ons i der th e fi rs t call (f(0)): T h e typ e of th e arg u m ent i s int , wh i ch m atch es th e typ e of th e p aram eter of th e fi rs t tem p late i f we s u bs ti tu te T wi th int. H owev er, th e p aram eter typ e of th e s econd tem p late i s always a p oi nter and, h ence, after dedu cti on, only an i ns tance g enerated from th e fi rs t tem p late i s a candi date for th e call. I n th i s cas e ov erload res olu ti on i s tri v i al.

T h e s econd call (f((int*)0)) i s m ore i nteres ti ng : A rg u m ent dedu cti on s u cceeds for both tem p lates , yi eldi ng th e fu ncti ons f<int*>(int*) and f<int>(int*). F rom a tradi ti onal ov erload res olu ti on p ers p ecti v e, both are eq u ally g ood fu ncti ons to call wi th an int* arg u m ent, wh i ch wou ld s u g g es t th at th e call i s am bi g u ou s (s ee A p p endi x B ). H owev er, i n th i s s ort of cas e an addi ti onal ov erload res olu ti on cri teri on com es i nto p lay: T h e fu ncti on g enerated from th e " m ore s p eci ali z ed" tem p late i s s elected. H ere (as we s ee s h ortly), th e s econd tem p late i s cons i dered " m ore s p eci ali z ed" and th u s th e ou tp u t of ou r ex am p le i s (ag ai n):

1 2

12.2.3 Formal Ordering Rules

I n ou r las t ex am p le i t m ay s eem v ery i ntu i ti v e th at th e s econd tem p late i s " m ore s p eci al" th an th e fi rs t becau s e th e fi rs t can accom m odate j u s t abou t any arg u m ent typ e wh ereas th e s econd allows only p oi nter typ es . H owev er, oth er ex am p les are not neces s ari ly as i ntu i ti v e. I n wh at follows , we des cri be th e ex act p rocedu re to determ i ne wh eth er one fu ncti on tem p late p arti ci p ati ng i n an ov erload s et i s m ore s p eci ali z ed th an th e oth er. H owev er, note th at th es e are par ti al orderi ng ru les : I t i s p os s i ble th at g i v en two tem p lates nei th er can be cons i dered m ore s p eci ali z ed th an th e oth er. I f ov erload res olu ti on m u s t s elect between two s u ch tem p lates , no deci s i on can be m ade, and th e p rog ram contai ns an am bi g u i ty error.

L et' s as s u m e we are com p ari ng two i denti cally nam ed fu ncti on tem p lates ft1 and ft2 th at s eem v i able for a g i v en fu ncti on call. F u ncti on call p aram eters th at are cov ered by a defau lt arg u m ent and elli p s i s p aram eters th at are not u s ed are i g nored i n wh at follows . W e th en s ynth es i z e two arti fi ci al li s ts of arg u m ent typ es (or for conv ers i on fu ncti on tem p lates , a retu rn typ e) by s u bs ti tu ti ng ev ery

Page 232: CPlusPlus Templates The Complete Guide

tem p late p aram eter as follows :

1. R e p l a c e e a c h t e m p l a t e t y p e p a r a m e t e r w i t h a u n i q u e " m a d e u p " t y p e . 2 . R e p l a c e e a c h t e m p l a t e t e m p l a t e p a r a m e t e r w i t h a u n i q u e " m a d e u p " c l a s s t e m p l a t e . 3 . R e p l a c e e a c h n o n t y p e t e m p l a t e p a r a m e t e r w i t h a u n i q u e " m a d e u p " v a l u e o f t h e a p p r o p r i a t e t y p e .

I f tem p late arg u m ent dedu cti on of th e s econd tem p late ag ai ns t th e fi rs t s ynth es i z ed li s t of arg u m ent typ es s u cceeds wi th an ex act m atch , bu t not v i ce v ers a, th en th e fi rs t tem p late i s s ai d to be mor e spec i ali z ed th an th e s econd. C onv ers ely, i f tem p late arg u m ent dedu cti on of th e fi rs t tem p late ag ai ns t th e s econd s ynth es i z ed li s t of arg u m ent typ es s u cceeds wi th an ex act m atch , bu t not v i ce v ers a, th en th e s econd tem p late i s s ai d to be mor e spec i ali z ed th an th e fi rs t. O th erwi s e (ei th er no dedu cti on s u cceeds or both s u cceed), th ere i s no orderi ng between th e two tem p lates .

L et' s m ak e th i s concrete by ap p lyi ng i t to th e two tem p lates i n ou r las t ex am p le. F rom th es e two tem p lates we s ynth es i z e two li s ts of arg u m ent typ es by rep laci ng th e tem p late p aram eters as des cri bed earli er: (A1) and (A2*) (wh ere A1 and A2 are u ni q u e m ade u p typ es ). C learly, dedu cti on of th e fi rs t tem p late ag ai ns t th e s econd li s t of arg u m ent typ es s u cceeds by s u bs ti tu ti ng A2* for T. H owev er, th ere i s no way to m ak e T* of th e s econd tem p late m atch th e nonp oi nter typ e A1 i n th e fi rs t li s t. H ence, we form ally conclu de th at th e s econd tem p late i s m ore s p eci ali z ed th an th e fi rs t.

F i nally, cons i der a m ore i ntri cate ex am p le i nv olv i ng m u lti p le fu ncti on p aram eters :

template<typename T> void t(T*, T const* = 0, ...); template<typename T> void t(T const*, T*, T* = 0); void example(int* p) { t(p, p); }

F i rs t, becau s e th e actu al call does not u s e th e elli p s i s p aram eter for th e fi rs t tem p late and th e las t p aram eter of th e s econd tem p late i s cov ered by i ts defau lt arg u m ent, th es e p aram eters are i g nored i n th e p arti al orderi ng . N ote th at th e defau lt arg u m ent of th e fi rs t tem p late i s not u s ed; h ence th e corres p ondi ng p aram eter p arti ci p ates i n th e orderi ng .

T h e s ynth es i z ed li s ts of arg u m ent typ es are (A1*, A1 const*) and (A2 const*, A2*). T em p late arg u m ent dedu cti on of (A1*, A1 const*) v ers u s th e s econd tem p late actu ally s u cceeds wi th th e s u bs ti tu ti on of T wi th A1 const , bu t th e res u lti ng m atch i s not ex act becau s e a q u ali fi cati on adj u s tm ent i s needed

Page 233: CPlusPlus Templates The Complete Guide

to call t<A1 const>(A1 const*, A1 const*, A1 const* = 0) wi th arg u m ents of typ es (A1*, A1 const*). Si m i larly, no ex act m atch can be fou nd by dedu ci ng tem p late arg u m ents for th e fi rs t tem p late from th e arg u m ent typ e li s t (A2 const*, A2*). T h erefore, th ere i s no orderi ng relati ons h i p between th e two tem p lates , and th e call i s am bi g u ou s .

T h e form al orderi ng ru les g enerally res u lt i n th e i ntu i ti v e s electi on of fu ncti on tem p lates . O nce i n a wh i le, h owev er, an ex am p le com es u p for wh i ch th e ru les do not s elect th e i ntu i ti v e ch oi ce. I t i s th erefore p os s i ble th at th e ru les wi ll be rev i s ed to accom m odate th os e ex am p les i n th e fu tu re.

12.2.4 Templates and Nontemplates

F u ncti on tem p lates can be ov erloaded wi th nontem p late fu ncti ons . A ll els e bei ng eq u al, th e nontem p late fu ncti on i s p referred i n s electi ng th e actu al fu ncti on bei ng called. T h e followi ng ex am p le i llu s trates th i s :

// details/nontmpl.cpp #include <string> #include <iostream> template<typename T> std::string f(T) { return "Template"; } std::string f(int&) { return "Nontemplate"; } int main() { int x = 7; std::cout << f(x) << std::endl; }

T h i s s h ou ld ou tp u t:

Nontemplate

Page 234: CPlusPlus Templates The Complete Guide

12.3 Explicit Specialization

T h e abi li ty to ov erload fu ncti on tem p lates , com bi ned wi th th e p arti al orderi ng ru les to s elect th e " bes t" m atch i ng fu ncti on tem p late, allows u s to add m ore s p eci ali z ed tem p lates to a g eneri c i m p lem entati on to tu ne code trans p arently for g reater effi ci ency. H owev er, clas s tem p lates cannot be ov erloaded. I ns tead, anoth er m ech ani s m was ch os en to enable trans p arent cu s tom i z ati on of clas s tem p lates : ex pli c i t spec i ali z ati on . T h e s tandard term ex pli c i t spec i ali z ati on refers to a lang u ag e featu re th at we call f u ll spec i ali z ati on i ns tead. I t p rov i des an i m p lem entati on for a tem p late wi th tem p late p aram eters th at are fu lly s u bs ti tu ted: N o tem p late p aram eters rem ai n. C las s tem p lates and fu ncti on tem p lates can be fu lly s p eci ali z ed. So can m em bers of clas s tem p lates th at m ay be defi ned ou ts i de th e body of a clas s defi ni ti on (i .e., m em ber fu ncti ons , nes ted clas s es , and s tati c data m em bers ).

I n a later s ecti on, we wi ll des cri be par ti al spec i ali z ati on . T h i s i s s i m i lar to fu ll s p eci ali z ati on, bu t i ns tead of fu lly s u bs ti tu ti ng th e tem p late p aram eters , s om e p aram eteri z ati on i s left i n th e alternati v e i m p lem entati on of a tem p late. F u ll s p eci ali z ati ons and p arti al s p eci ali z ati ons are both eq u ally " ex p li ci t" i n ou r s ou rce code, wh i ch i s wh y we av oi d th e term ex pli c i t spec i ali z ati on i n ou r di s cu s s i on. N ei th er fu ll nor p arti al s p eci ali z ati on i ntrodu ces a totally new tem p late or tem p late i ns tance. I ns tead, th es e cons tru cts p rov i de alternati v e defi ni ti ons for i ns tances th at are already i m p li ci tly declared i n th e g eneri c (or u n spec i ali z ed ) tem p late. T h i s i s a relati v ely i m p ortant concep tu al obs erv ati on, and i t i s a k ey di fference wi th ov erloaded tem p lates .

12.3.1 Full Class Template Specialization

A fu ll s p eci ali z ati on i s i ntrodu ced wi th a s eq u ence of th ree tok ens : template, <, and >. [3 ] I n addi ti on, th e clas s nam e declarator i s followed by th e tem p late arg u m ents for wh i ch th e s p eci ali z ati on i s declared. T h e followi ng ex am p le i llu s trates th i s :

[3 ] T h e s am e p refi x i s als o needed to declare fu ll fu ncti on tem p late s p eci ali z ati ons . E arli er des i g ns of th e C + + lang u ag e di d not i nclu de th i s p refi x , bu t th e addi ti on of m em ber tem p lates req u i red addi ti onal s yntax to di s am bi g u ate com p lex s p eci ali z ati on cas es .

template<typename T> class S { public: void info() { std::cout << "generic (S<T>::info())\n"; }

Page 235: CPlusPlus Templates The Complete Guide

}; template<> class S<void> { public: void msg() { std::cout << "fully specialized (S<void>::msg())\n"; } };

N ote h ow th e i m p lem entati on of th e fu ll s p eci ali z ati on does not need to be related i n any way to th e g eneri c defi ni ti on: T h i s allows u s to h av e m em ber fu ncti ons of di fferent nam es (info v ers u s msg). T h e connecti on i s s olely determ i ned by th e nam e of th e clas s tem p late.

T h e li s t of s p eci fi ed tem p late arg u m ents m u s t corres p ond to th e li s t of tem p late p aram eters . F or ex am p le, i t i s not v ali d to s p eci fy a nontyp e v alu e for a tem p late typ e p aram eter. H owev er, tem p late arg u m ents for p aram eters wi th defau lt tem p late arg u m ents are op ti onal:

template<typename T> class Types { public: typedef int I; }; template<typename T, typename U = typename Types<T>::I> class S; // (1) template<> class S<void> { // (2) public: void f(); }; template<> class S<char, char>; // (3) template<> class S<char, 0>; // ERROR: 0 cannot substitute U int main() { S<int>* pi; // OK: uses (1), no definition needed S<int> e1; // ERROR: uses (1), but no definition available S<void>* pv; // OK: uses (2) S<void,int> sv; // OK: uses (2), definition available S<void,char> e2; // ERROR: uses (1), but no definition available S<char,char> e3; // ERROR: uses (3), but no definition available } template<> class S<char, char> { // definition for (3) };

Page 236: CPlusPlus Templates The Complete Guide

A s th i s ex am p le als o s h ows , declarati ons of fu ll s p eci ali z ati ons (and of tem p lates ) do not neces s ari ly h av e to be defi ni ti ons . H owev er, wh en a fu ll s p eci ali z ati on i s declared, th e g eneri c defi ni ti on i s nev er u s ed for th e g i v en s et of tem p late arg u m ents . H ence, i f a defi ni ti on i s needed bu t none i s p rov i ded, th e p rog ram i s i n error. F or clas s tem p late s p eci ali z ati on i t i s s om eti m es u s efu l to " forward declare" typ es s o th at m u tu ally dep endent typ es can be cons tru cted. A fu ll s p eci ali z ati on declarati on i s i denti cal to a norm al clas s declarati on i n th i s way (i t i s n ot a tem p late declarati on). T h e only di fferences are th e s yntax and th e fact th at th e declarati on m u s t m atch a p rev i ou s tem p late declarati on. B ecau s e i t i s not a tem p late declarati on, th e m em bers of a fu ll clas s tem p late s p eci ali z ati on can be defi ned u s i ng th e ordi nary ou t-of-clas s m em ber defi ni ti on s yntax (i n oth er words , th e template<> p refi x cannot be s p eci fi ed):

template<typename T> class S; template<> class S<char**> { public: void print() const; }; // the following definition cannot be preceded by template<> void S<char**>::print() { std::cout << "pointer to pointer to char\n"; }

A m ore com p lex ex am p le m ay rei nforce th i s noti on:

template<typename T> class Outside { public: template<typename U> class Inside { }; }; template<> class Outside<void> { // there is no special connection between the following nested class // and the one defined in the generic template template<typename U> class Inside { private: static int count; }; }; // the following definition cannot be preceded by template<> template<typename U> int Outside<void>::Inside<U>::count = 1;

Page 237: CPlusPlus Templates The Complete Guide

A fu ll s p eci ali z ati on i s a rep lacem ent for th e i ns tanti ati on of a certai n g eneri c tem p late, and i t i s not v ali d to h av e both th e ex p li ci t and th e g enerated v ers i ons of a tem p late p res ent i n th e s am e p rog ram . A n attem p t to u s e both i n th e s am e fi le i s u s u ally cau g h t by a com p i ler:

template <typename T> class Invalid { }; Invalid<double> x1; // causes the instantiation of Invalid<double> template<> class Invalid<double>; // ERROR: Invalid<double> already instantiated!

U nfortu nately, i f th e u s es occu r i n di fferent trans lati on u ni ts , th e p roblem m ay not be cau g h t s o eas i ly. T h e followi ng i nv ali d C + + ex am p le cons i s ts of two fi les and com p i les and li nk s on m any i m p lem entati ons , bu t i t i s i nv ali d and dang erou s :

// Translation unit 1: template<typename T> class Danger { public: enum { max = 10; }; }; char buffer[Danger<void>::max]; // uses generic value extern void clear(char const*); int main() { clear(buffer); } // Translation unit 2: template<typename T> class Danger; template<> class Danger<void> { public: enum { max = 100; }; }; void clear(char const* buf) { // mismatch in array bound! for(intk=0;k<Danger<void>::max; ++k) { buf[k] = '\0'; } }

T h i s ex am p le i s clearly contri v ed to k eep i t s h ort, bu t i t i llu s trates th at care m u s t

Page 238: CPlusPlus Templates The Complete Guide

be tak en to ens u re th at th e declarati on of th e s p eci ali z ati on i s v i s i ble to all th e u s ers of th e g eneri c tem p late. I n p racti cal term s , th i s m eans th at a declarati on of th e s p eci ali z ati on s h ou ld norm ally follow th e declarati on of th e tem p late i n i ts h eader fi le. W h en th e g eneri c i m p lem entati on com es from an ex ternal s ou rce (s u ch th at th e corres p ondi ng h eader fi les s h ou ld not be m odi fi ed), th i s i s not neces s ari ly p racti cal, bu t i t m ay be worth creati ng a h eader i nclu di ng th e g eneri c tem p late followed by declarati ons of th e s p eci ali z ati ons to av oi d th es e h ard-to-fi nd errors . W e fi nd th at, i n g eneral, i t i s better to av oi d s p eci ali z i ng tem p lates com i ng from an ex ternal s ou rce u nles s i t i s clearly m ark ed as bei ng des i g ned for th at p u rp os e.

12.3.2 Full Function Template Specialization

T h e s yntax and p ri nci p les beh i nd (ex p li ci t) fu ll fu ncti on tem p late s p eci ali z ati on are m u ch th e s am e as th os e for fu ll clas s tem p late s p eci ali z ati on, bu t ov erloadi ng and arg u m ent dedu cti on com e i nto p lay.

T h e fu ll s p eci ali z ati on declarati on can om i t ex p li ci t tem p late arg u m ents wh en th e tem p late bei ng s p eci ali z ed can be determ i ned v i a arg u m ent dedu cti on (u s i ng as arg u m ent typ es th e p aram eter typ es p rov i ded i n th e declarati on) and p arti al orderi ng . F or ex am p le:

template<typename T> int f(T) // (1) { return 1; } template<typename T> int f(T*) // (2) { return 2; } template<> int f(int) // OK: specialization of (1) { return 3; } template<> int f(int*) // OK: specialization of (2) { return 4; }

A fu ll fu ncti on tem p late s p eci ali z ati on cannot i nclu de defau lt arg u m ent v alu es . H owev er, any defau lt arg u m ents th at were s p eci fi ed for th e tem p late bei ng s p eci ali z ed rem ai n ap p li cable to th e ex p li ci t s p eci ali z ati on:

template<typename T> int f(T, T x = 42)

Page 239: CPlusPlus Templates The Complete Guide

{ return x; } template<> int f(int, int = 35) // ERROR! { return 0; } template<typename T> int g(T, T x = 42) { return x; } template<> int g(int, int y) { return y/2; } int main() { std::cout << f(0) << std::endl; // should print 21 }

A fu ll s p eci ali z ati on i s i n m any ways s i m i lar to a norm al declarati on (or rath er, a norm al r edeclarati on). I n p arti cu lar, i t does not declare a tem p late, and th erefore only one d ef i n i ti on of a noni nli ne fu ll fu ncti on tem p late s p eci ali z ati on s h ou ld ap p ear i n a p rog ram . H owev er, we m u s t s ti ll ens u re th at a d ec lar ati on of th e fu ll s p eci ali z ati on follows th e tem p late to p rev ent attem p ts at u s i ng th e fu ncti on g enerated from th e tem p late. T h e declarati ons for tem p late g i n th e p rev i ou s ex am p le wou ld th erefore typ i cally be org ani z ed i n two fi les . T h e i nterface fi le m i g h t look as follows :

#ifndef TEMPLATE_G_HPP #define TEMPLATE_G_HPP // template definition should appear in header file: template<typename T> int g(T, T x = 42) { return x; } // specialization declaration inhibits instantiations of the template; // definition should not appear here to avoid multiple definition errors template<> int g(int, int y); #endif // TEMPLATE_G_HPP

T h e corres p ondi ng i m p lem entati on fi le m ay read:

Page 240: CPlusPlus Templates The Complete Guide

#include "template_g.hpp" template<> int g(int, int y) { return y/2; }

A lternati v ely, th e s p eci ali z ati on cou ld be m ade i nli ne, i n wh i ch cas e i ts defi ni ti on can be (and s h ou ld be) p laced i n th e h eader fi le.

12.3.3 Full Member Specialization

N ot only m em ber tem p lates , bu t als o ordi nary s tati c data m em bers and m em ber fu ncti ons of clas s tem p lates , can be fu lly s p eci ali z ed. T h e s yntax req u i res template<> p refi x for ev ery enclos i ng clas s tem p late. I f a m em ber tem p late i s bei ng s p eci ali z ed, a template<> m u s t als o be added to denote i t i s bei ng s p eci ali z ed. T o i llu s trate th e i m p li cati ons of th i s , let' s as s u m e th e followi ng declarati ons :

template<typename T> class Outer { // (1) public: template<typename U> class Inner { // (2) private: static int count; // (3) }; static int code; // (4) void print() const { // (5) std::cout << "generic"; } }; template<typename T> int Outer<T>::code = 6; // (6) template<typename T> template<typename U> int Outer<T>::Inner<U>::count = 7; // (7) template<> class Outer<bool> { // (8) public: template<typename U> class Inner { // (9) private: static int count; // (10) }; void print() const { // (11) } };

T h e ordi nary m em bers code at p oi nt (4 ) and print() at p oi nt (5 ) of th e g eneri c Outer tem p late (1) h av e a s i ng le enclos i ng clas s tem p late and h ence need one template<> p refi x to s p eci ali z e th em fu lly for a s p eci fi c s et of tem p late

Page 241: CPlusPlus Templates The Complete Guide

arg u m ents :

template<> int Outer<void>::code = 12; template<> void Outer<void>::print() { std::cout << "Outer<void>"; }

T h es e defi ni ti ons are u s ed ov er th e g eneri c ones at p oi nts (4 ) and (5 ) for clas s Outer<void>, bu t oth er m em bers of clas s Outer<void> are s ti ll g enerated from th e tem p late at p oi nt (1). N ote th at after th es e declarati ons i t i s no long er v ali d to p rov i de an ex p li ci t s p eci ali z ati on for Outer<void>.

J u s t as wi th fu ll fu ncti on tem p late s p eci ali z ati ons , we need a way to declare th e s p eci ali z ati on of an ordi nary m em ber of a clas s tem p late wi th ou t s p eci fyi ng a defi ni ti on (to p rev ent m u lti p le defi ni ti ons ). A lth ou g h nondefi ni ng ou t-of-clas s declarati ons are not allowed i n C + + for m em ber fu ncti ons and s tati c data m em bers of ordi nary clas s es , th ey ar e fi ne wh en s p eci ali z i ng m em bers of clas s tem p lates . T h e p rev i ou s defi ni ti ons cou ld be declared wi th

template<> int Outer<void>::code; template<> void Outer<void>::print();

T h e attenti v e reader m i g h t p oi nt ou t th at th e nondefi ni ng declarati on of th e fu ll s p eci ali z ati on of Outer<void>::code h as ex actly th e s am e s yntax as th at req u i red to p rov i de a defi ni ti on to be i ni ti ali z ed wi th a defau lt cons tru ctor. T h i s i s i ndeed s o, bu t s u ch declarati ons are always i nterp reted as nondefi ni ng declarati ons .

T h erefore, th ere i s no way to p rov i de a defi ni ti on for th e fu ll s p eci ali z ati on of a s tati c data m em ber wi th a typ e th at can only be i ni ti ali z ed u s i ng a defau lt cons tru ctor!

class DefaultInitOnly { public: DefaultInitOnly() { } private: DefaultInitOnly(DefaultInitOnly const&); // no copying possible }; template<typename T> class Statics {

Page 242: CPlusPlus Templates The Complete Guide

private: T sm; }; // the following is a declaration; // no syntax exists to provide a definition template<> DefaultInitOnly Statics<DefaultInitOnly>::sm;

T h e m em ber tem p late Outer<T>::Inner can als o be s p eci ali z ed for a g i v en tem p late arg u m ent wi th ou t affecti ng th e oth er m em bers of th e s p eci fi c i ns tanti ati on of Outer<T>, for wh i ch we are s p eci ali z i ng th e m em ber tem p late. A g ai n, becau s e th ere i s one enclos i ng tem p late, we wi ll need one template<> p refi x . T h i s res u lts i n code li k e th e followi ng :

template<> template<typename X> class Outer<wchar_t>::Inner { public: static long count; // member type changed }; template<> template<typename X> long Outer<wchar_t>::Inner<X>::count;

T h e tem p late Outer<T>::Inner can als o be fu lly s p eci ali z ed, bu t only for a g i v en i ns tance of Outer<T>. W e now need two template<> p refi x es : one becau s e of th e enclos i ng clas s and one becau s e we' re fu lly s p eci ali z i ng th e (i nner) tem p late:

template<> template<> class Outer<char>::Inner<wchar_t> { public: enum { count = 1; }; }; // the following is not valid C++: // template<> cannot follow a template parameter list template<typename X> template<> class Outer<X>::Inner<void>; // ERROR!

C ontras t th i s wi th th e s p eci ali z ati on of th e m em ber tem p late of Outer<bool>. B ecau s e th e latter i s already fu lly s p eci ali z ed, th ere i s no enclos i ng tem p late, and we need only one template<> p refi x :

template<> class Outer<bool>::Inner<wchar_t> { public: enum { count = 2; };

Page 243: CPlusPlus Templates The Complete Guide

};

Page 244: CPlusPlus Templates The Complete Guide

12.4 Partial Class Template Specialization

F u ll tem p late s p eci ali z ati on i s often u s efu l, bu t s om eti m es i t i s natu ral to want to s p eci ali z e a clas s tem p late for a fam i ly of tem p late arg u m ents rath er th an j u s t one s p eci fi c s et of tem p late arg u m ents . F or ex am p le, let' s as s u m e we h av e a clas s tem p late i m p lem enti ng a li nk ed li s t:

template<typename T> class List { // (1) public: … void append(T const&); inline size_t length() const; … };

A larg e p roj ect m ak i ng u s e of th i s tem p late m ay i ns tanti ate i ts m em bers for m any typ es . F or m em ber fu ncti ons th at are not ex p anded i nli ne (s ay, List<T>::append()), th i s m ay cau s e noti ceable g rowth i n th e obj ect code. H owev er, we m ay k now th at from a low-lev el p oi nt of v i ew, th e code for List<int*>::append() and List<void*>::append() i s th e s am e. I n oth er words , we' d li k e to s p eci fy th at all List s of p oi nters s h are an i m p lem entati on. A lth ou g h th i s cannot be ex p res s ed i n C + + , we can ach i ev e s om eth i ng q u i te clos e by s p eci fyi ng th at all List s of p oi nters s h ou ld be i ns tanti ated from a di fferent tem p late defi ni ti on:

template<typename T> class List<T*> { // (2) private: List<void*> impl; … public: … void append(T* p) { impl.append(p); } size_t length() const { return impl.length(); } … };

I n th i s contex t, th e ori g i nal tem p late at p oi nt (1) i s called th e pr i mar y template , and th e latter defi ni ti on i s called a par ti al spec i al i z ati on (becau s e th e tem p late arg u m ents for wh i ch th i s tem p late defi ni ti on m u s t be u s ed h av e been only p arti ally s p eci fi ed). T h e s yntax th at ch aracteri z es a p arti al s p eci ali z ati on i s th e

Page 245: CPlusPlus Templates The Complete Guide

com bi nati on of a tem p late p aram eter li s t declarati on (template<...>) and a s et of ex p li ci tly s p eci fi ed tem p late arg u m ents on th e nam e of th e clas s tem p late (<T*> i n ou r ex am p le).

O u r code contai ns a p roblem becau s e List<void*> recu rs i v ely contai ns a m em ber of th at s am e List<void*> typ e. T o break th e cycle, we can p recede th e p rev i ou s p arti al s p eci ali z ati on wi th a fu ll s p eci ali z ati on:

template<> class List<void*> { // (3) … void append (void* p); inline size_t length() const; … };

T h i s work s becau s e m atch i ng fu ll s p eci ali z ati ons are p referred ov er p arti al s p eci ali z ati ons . A s a res u lt, all m em ber fu ncti ons of List s of p oi nters are forwarded (th rou g h eas i ly i nli neable fu ncti ons ) to th e i m p lem entati on of List<void*>. T h i s i s an effecti v e way to com bat s o-called c od e b loat (of wh i ch C + + tem p lates are often accu s ed).

T h ere ex i s ts a nu m ber of li m i tati ons on th e p aram eter and arg u m ent li s ts of p arti al s p eci ali z ati on declarati ons . Som e of th em are as follows :

1. Th e a r g u m e n t s o f t h e p a r t i a l s p e c i a l i z a t i o n m u s t m a t c h i n k i n d ( t y p e , n o n t y p e , o r t e m p l a t e ) t h e c o r r e s p o n d i n g p a r a m e t e r s o f t h e p r i m a r y t e m p l a t e .

2 . Th e p a r a m e t e r l i s t o f t h e p a r t i a l s p e c i a l i z a t i o n c a n n o t h a v e d e f a u l t a r g u m e n t s ; t h e d e f a u l t a r g u m e n t s o f t h e p r i m a r y c l a s s t e m p l a t e a r e u s e d i n s t e a d .

3 . Th e n o n t y p e a r g u m e n t s o f t h e p a r t i a l s p e c i a l i z a t i o n s h o u l d e i t h e r b e n o n d e p e n d e n t v a l u e s o r p l a i n n o n t y p e t e m p l a t e p a r a m e t e r s . Th e y c a n n o t b e m o r e c o m p l e x d e p e n d e n t e x p r e s s i o n s l i k e 2*N ( w h e r e N i s a t e m p l a t e p a r a m e t e r ) .

4 . Th e l i s t o f t e m p l a t e a r g u m e n t s o f t h e p a r t i a l s p e c i a l i z a t i o n s h o u l d n o t b e i d e n t i c a l ( i g n o r i n g r e n a m i n g ) t o t h e l i s t o f p a r a m e t e r s o f t h e p r i m a r y t e m p l a t e .

A n ex am p le i llu s trates th es e li m i tati ons :

template<typename T, int I = 3> class S; // primary template template<typename T> class S<int, T>; // ERROR: parameter kind mismatch template<typename T = int> class S<T, 10>; // ERROR: no default arguments template<int I> class S<int, I*2>; // ERROR: no nontype expressions template<typename U, int K> class S<U, K>; // ERROR: no significant difference

Page 246: CPlusPlus Templates The Complete Guide

// from primary template

E v ery p arti al s p eci ali z ati on—li k e ev ery fu ll s p eci ali z ati on—i s as s oci ated wi th th e p ri m ary tem p late. W h en a tem p late i s u s ed, th e p ri m ary tem p late i s always th e one th at i s look ed u p , bu t th en th e arg u m ents are als o m atch ed ag ai ns t th os e of th e as s oci ated s p eci ali z ati ons to determ i ne wh i ch tem p late i m p lem entati on i s p i ck ed. I f m u lti p le m atch i ng s p eci ali z ati ons are fou nd, th e " m os t s p eci ali z ed" one (i n th e s ens e defi ned for ov erloaded fu ncti on tem p lates ) i s s elected; i f none can be called " m os t s p eci ali z ed, " th e p rog ram contai ns an am bi g u i ty error.

F i nally, we s h ou ld p oi nt ou t th at i t i s enti rely p os s i ble for a clas s tem p late p arti al s p eci ali z ati on to h av e m ore p aram eters th an th e p ri m ary tem p late. C ons i der ou r g eneri c tem p late List (declared at p oi nt (1)) ag ai n. W e h av e already di s cu s s ed h ow to op ti m i z e th e li s t-of-p oi nters cas e, bu t we m ay want to do th e s am e wi th certai n p oi nter-to-m em ber typ es . T h e followi ng code ach i ev es th i s for p oi nter-to-m em ber-p oi nters :

template<typename C> class List<void* C::*> { // (4) public: // partial specialization for any pointer-to-void* member // every other pointer-to-member-pointer type will use this typedef void* C::*ElementType; … void append(ElementType pm); inline size_t length() const; … }; template<typename T, typename C> class List<T* C::*> { // (5) private: List<void* C::*> impl; … public: // partial specialization for any pointer-to-member-pointer type // except pointer-to-void* member which is handled earlier; // note that this partial specialization has two template parameters, // whereas the primary template only has one parameter typedef T* C::*ElementType; … void append(ElementType pm) { impl.append((void* C::*)pm); } inline size_t length() const { return impl.length(); } … };

I n addi ti on to ou r obs erv ati on reg ardi ng th e nu m ber of tem p late p aram eters , note th at th e com m on i m p lem entati on defi ned at (4 ) to wh i ch all oth ers are forwarded (by th e declarati on at p oi nt (5 )) i s i ts elf a p arti al s p eci ali z ati on (for th e

Page 247: CPlusPlus Templates The Complete Guide

s i m p le p oi nter cas e i t i s a fu ll s p eci ali z ati on). H owev er, i t i s clear th at th e s p eci ali z ati on at p oi nt (4 ) i s m ore s p eci ali z ed th an th at at p oi nt (5 ); th u s no am bi g u i ty s h ou ld occu r.

Page 248: CPlusPlus Templates The Complete Guide

12.5 Afternotes

F u ll tem p late s p eci ali z ati on was p art of th e C + + tem p late m ech ani s m from th e s tart. F u ncti on tem p late ov erloadi ng and clas s tem p late p arti al s p eci ali z ati on, on oth er h and, cam e m u ch later. T h e H P aC + + com p i ler was th e fi rs t to i m p lem ent fu ncti on tem p late ov erloadi ng , and E D G ' s C + + front end was th e fi rs t to i m p lem ent clas s tem p late p arti al s p eci ali z ati on. T h e p arti al orderi ng p ri nci p les des cri bed i n th i s ch ap ter were ori g i nally i nv ented by Stev e A dam cz yk and J oh n Sp i cer (wh o are both of E D G ).

T h e abi li ty of tem p late s p eci ali z ati ons to term i nate an oth erwi s e i nfi ni tely recu rs i v e tem p late defi ni ti on (s u ch as th e List<T*> ex am p le p res ented i n Secti on 12.4 on p ag e 200) was k nown for a long ti m e. H owev er, E rwi n U nru h was p erh ap s th e fi rs t to note th at th i s cou ld lead to th e i nteres ti ng noti on of template metapr og r ammi n g : U s i ng th e tem p late i ns tanti ati on m ech ani s m to p erform nontri v i al com p u tati ons at com p i le ti m e. W e dev ote C h ap ter 17 to th i s top i c.

Y ou m ay leg i ti m ately wonder wh y only clas s tem p lates can be p arti ally s p eci ali z ed. T h e reas ons are m os tly h i s tori cal. I t i s p robably p os s i ble to defi ne th e s am e m ech ani s m for fu ncti on tem p lates (s ee C h ap ter 13 ). I n s om e ways th e effect of ov erloadi ng fu ncti on tem p lates i s s i m i lar, bu t th ere are als o s om e s u btle di fferences . T h es e di fferences are m os tly related to th e fact th at only th e p ri m ary tem p late needs to be look ed u p wh en a u s e i s encou ntered. T h e s p eci ali z ati ons are cons i dered only afterward, to determ i ne wh i ch i m p lem entati on s h ou ld be u s ed. I n contras t, all ov erloaded fu ncti on tem p lates m u s t be brou g h t i nto an ov erload s et by look i ng th em u p , and th ey m ay com e from di fferent nam es p aces or clas s es . T h i s i ncreas es th e li k eli h ood of u ni ntenti onally ov erloadi ng a tem p late nam e s om ewh at.

C onv ers ely, i t i s als o i m ag i nable to allow a form of ov erloadi ng of clas s tem p lates . H ere i s an ex am p le:

// invalid overloading of class templates template<typename T1, typename T2> class Pair; template<int N1, int N2> class Pair;

H owev er, th ere does n' t s eem to be a p res s i ng need for s u ch a m ech ani s m .

Page 249: CPlusPlus Templates The Complete Guide

Chapter 13. Future Directions

C + + tem p lates ev olv ed cons i derably from th ei r i ni ti al des i g n i n 19 8 8 u nti l th e s tandardi z ati on of C + + i n 19 9 8 (th e tech ni cal work was com p leted i n N ov em ber 19 9 7 ). A fter th at, th e lang u ag e defi ni ti on was s table for s ev eral years , bu t du ri ng th at ti m e v ari ou s new needs h av e ari s en i n th e area of C + + tem p lates . Som e of th es e needs are s i m p ly a cons eq u ence of a des i re for m ore cons i s tency or orth og onali ty i n th e lang u ag e. F or ex am p le, wh y wou ldn' t defau lt tem p late arg u m ents be allowed on fu ncti on tem p lates wh en th ey are allowed on clas s tem p lates ? O th er ex tens i ons are p rom p ted by i ncreas i ng ly s op h i s ti cated tem p late p rog ram m i ng i di om s th at often s tretch th e abi li ti es of ex i s ti ng com p i lers .

I n wh at follows we des cri be s om e ex tens i ons th at h av e com e u p m ore th an once am ong C + + lang u ag e and com p i ler des i g ners . O ften s u ch ex tens i ons were p rom p ted by th e des i g ners of v ari ou s adv anced C + + li brari es (i nclu di ng th e C + + s tandard li brary). T h ere i s no g u arantee th at any of th es e wi ll ev er be p art of s tandard C + + . O n th e oth er h and, s om e of th es e are already p rov i ded as ex tens i ons by certai n C + + i m p lem entati ons .

Page 250: CPlusPlus Templates The Complete Guide

13.1 The Angle Bracket Hack

A m ong th e m os t com m on s u rp ri s es for beg i nni ng tem p late p rog ram m ers i s th e neces s i ty to add s om e blank s p ace between cons ecu ti v e clos i ng ang le brack ets . F or ex am p le:

#include <list> #include <vector> typedef std::vector<std::list<int> > LineTable; // OK typedef std::vector<std::list<int>> OtherTable; // SYNTAX ERROR

T h e s econd typ edef declarati on i s an error becau s e th e two clos i ng ang le brack ets wi th no i nterv eni ng blank s p ace cons ti tu te a " ri g h t s h i ft" (>>) op erator, wh i ch m ak es no s ens e at th at locati on i n th e s ou rce.

Y et detecti ng s u ch an error and s i lently treati ng th e >> op erator as two clos i ng ang le brack ets (a featu re s om eti m es referred to as the an g le b r ac k et hac k ) i s relati v ely s i m p le com p ared wi th m any of th e oth er cap abi li ti es of C + + s ou rce code p ars ers . I ndeed, m any com p i lers are already able to recog ni z e s u ch s i tu ati ons and wi ll accep t th e code wi th a warni ng .

H ence, i t i s li k ely th at a fu tu re v ers i on of C + + wi ll req u i re th e declarati on of OtherTable (i n th e p rev i ou s ex am p le) to be v ali d. N ev erth eles s , we s h ou ld note th at th ere are s om e s u btle corners to th e ang le brack et h ack . I ndeed, th ere are s i tu ati ons wh en th e >> op erator i s a v ali d tok en wi th i n a tem p late arg u m ent li s t. T h e followi ng ex am p le i llu s trates th i s :

template<int N> class Buf; template<typename T> void strange() {} template<int N> void strange() {} int main() { strange<Buf<16>>2> >(); // the >> token is not an error }

A s om ewh at related i s s u e deals wi th th e acci dental u s e of th e di g rap h <: , wh i ch i s eq u i v alent to th e brack et [ (s ee Secti on 9 .3 .1 on p ag e 129 ). C ons i der th e followi ng code ex tract:

template<typename T> class List;

Page 251: CPlusPlus Templates The Complete Guide

class Marker; List<::Marker>* markers; // ERROR

T h e las t li ne of th i s ex am p le i s treated as List[:Marker>* markers;, wh i ch m ak es no s ens e at all. H owev er, a com p i ler cou ld concei v ably tak e i nto accou nt th at a tem p late s u ch as List can nev er v ali dly be followed by a left brack et and di s able th e recog ni ti on of th e corres p ondi ng di g rap h i n th at contex t.

Page 252: CPlusPlus Templates The Complete Guide

13.2 Relaxed typename Rules

Som e p rog ram m ers and lang u ag e des i g ners fi nd th e ru les for th e u s e of typename (s ee Secti on 5 .1 on p ag e 4 3 and Secti on 9 .3 .2 on p ag e 13 0) too s tri ct. F or ex am p le, i n th e followi ng code, th e occu rrence of typename i n typename Array<T>::ElementT i s m andatory, bu t th e one i n typename Array<int>::ElementT i s p roh i bi ted (an error):

template <typename T> class Array { public: typedef T ElementT; … }; template <typename T> void clear (typename Array<T>::ElementT& p); // OK template<> void clear (typename Array<int>::ElementT& p); // ERROR

E x am p les s u ch as th i s can be s u rp ri s i ng , and becau s e i t i s not di ffi cu lt for a C + + com p i ler i m p lem entati on s i m p ly to i g nore th e ex tra k eyword, th e lang u ag e des i g ners are cons i deri ng allowi ng th e typename k eyword i n front of any q u ali fi ed typ enam e th at i s not already elaborated wi th one of th e k eywords struct, class, union, or enum. Su ch a deci s i on wou ld p robably als o clari fy wh en th e .template , ->template, and ::template cons tru cts (s ee Secti on 9 .3 .3 on p ag e 13 2) are p erm i s s i ble.

I g nori ng ex traneou s u s es of typename and template i s relati v ely s trai g h tforward from an i m p lem enter' s p oi nt of v i ew. I nteres ti ng ly, th ere are als o s i tu ati ons wh en th e lang u ag e cu rrently req u i res th es e k eywords bu t wh en an i m p lem entati on cou ld do wi th ou t th em . F or ex am p le, i n th e p rev i ou s fu ncti on tem p late clear(), a com p i ler can k now th at th e nam e Array<T>::ElementT cannot be anyth i ng bu t a typ e nam e (no ex p res s i ons are allowed at th at p oi nt), and th erefore th e u s e of typename cou ld be m ade op ti onal i n th at s i tu ati on. T h e C + + s tandardi z ati on com m i ttee i s th erefore als o ex am i ni ng ch ang es th at wou ld redu ce th e nu m ber of s i tu ati ons wh en typename and template are req u i red.

Page 253: CPlusPlus Templates The Complete Guide

13.3 Default Function Template Arguments

W h en tem p lates were ori g i nally added to th e C + + lang u ag e, ex p li ci t fu ncti on tem p late arg u m ents were not a v ali d cons tru ct. F u ncti on tem p late arg u m ents always h ad to be dedu ci ble from th e call ex p res s i on. A s a res u lt, th ere s eem ed to be no com p elli ng reas on to allow defau lt fu ncti on tem p late arg u m ents becau s e th e defau lt wou ld always be ov erri dden by th e dedu ced v alu e.

Si nce th en, h owev er, i t i s p os s i ble to s p eci fy ex p li ci tly fu ncti on tem p late arg u m ents th at cannot be dedu ced. H ence, i t wou ld be enti rely natu ral to s p eci fy defau lt v alu es for th os e nondedu ci ble tem p late arg u m ents . C ons i der th e followi ng ex am p le:

template <typename T1, typename T2 = int> T2 count (T1 const& x); class MyInt { … }; void test (Container const& c) { int i = count(c); MyInt = count<MyInt>(c); assert(MyInt == i); }

I n th i s ex am p le, we h av e res p ected th e cons trai nt th at i f a tem p late p aram eter h as a defau lt arg u m ent v alu e, th en each p aram eter after th at m u s t h av e a defau lt tem p late arg u m ent too. T h i s cons trai nt i s needed for clas s tem p lates ; oth erwi s e, th ere wou ld be no way to s p eci fy trai li ng arg u m ents i n th e g eneral cas e. T h e followi ng erroneou s code i llu s trates th i s :

template <typename T1 = int, typename T2> class Bad; Bad<int>* b; // Is the given int a substitution for T1 or for T2?

F or fu ncti on tem p lates , h owev er, th e trai li ng arg u m ents m ay be dedu ced. H ence, th ere i s no tech ni cal di ffi cu lty i n rewri ti ng ou r ex am p le as follows :

template <typename T1 = int, typename T2> T1 count (T2 const& x); void test (Container const& c) { int i = count(c);

Page 254: CPlusPlus Templates The Complete Guide

MyInt = count<MyInt>(c); assert(MyInt == i); }

A t th e ti m e of th i s wri ti ng th e C + + s tandardi z ati on com m i ttee i s cons i deri ng ex tendi ng fu ncti on tem p lates i n th i s di recti on.

I n h i nds i g h t, p rog ram m ers h av e als o noted u s es th at do not i nv olv e ex p li ci t tem p late arg u m ents . F or ex am p le:

template <typename T = double> void f(T const& = T()); int main() { f(1); // OK: deduce T = int f<long>(2); // OK: T = long; no deduction f<char>(); // OK: same as f<char>('\0'); f(); // Same as f<double>(0.0); }

H ere a defau lt tem p late arg u m ent enables a defau lt call arg u m ent to ap p ly wi th ou t ex p li ci t tem p late arg u m ents .

Page 255: CPlusPlus Templates The Complete Guide

13.4 String Literal and Floating-Point Template Arguments

A m ong th e res tri cti ons on nontyp e tem p late arg u m ents , p erh ap s th e m os t s u rp ri s i ng to beg i nni ng and adv anced tem p late wri ters ali k e i s th e i nabi li ty to p rov i de a s tri ng li teral as a tem p late arg u m ent.

T h e followi ng ex am p le s eem s i ntu i ti v e enou g h :

template <char const* msg> class Diagnoser { public: void print(); }; int main() { Diagnoser<"Surprise!">().print(); }

H owev er, th ere are s om e p otenti al p roblem s . I n s tandard C + + , two i ns tances of Diagnoser are th e s am e typ e i f and only i f th ey h av e th e s am e arg u m ents . I n th i s cas e th e arg u m ent i s a p oi nter v alu e—i n oth er words , an addres s . H owev er, two i denti cal s tri ng li terals ap p eari ng i n di fferent s ou rce locati ons are not req u i red to h av e th e s am e addres s . W e cou ld th u s fi nd ou rs elv es i n th e awk ward s i tu ati on th at Diagnoser<"X"> and Diagnoser<"X"> are i n fact two di fferent and i ncom p ati ble typ es ! (N ote th at th e typ e of "X" i s char const[2], bu t i t decays to char const* wh en p as s ed as a tem p late arg u m ent.)

B ecau s e of th es e (and related) cons i derati ons , th e C + + s tandard p roh i bi ts s tri ng li terals as arg u m ents to tem p lates . H owev er, s om e i m p lem entati ons do offer th e faci li ty as an ex tens i on. T h ey enable th i s by u s i ng th e actu al s tri ng li teral contents i n th e i nternal rep res entati on of th e tem p late i ns tance. A lth ou g h th i s i s clearly feas i ble, s om e C + + lang u ag e com m entators feel th at a nontyp e tem p late p aram eter th at can be s u bs ti tu ted by a s tri ng li teral v alu e s h ou ld be declared di fferently from one th at can be s u bs ti tu ted by an addres s . A t th e ti m e of th i s wri ti ng , h owev er, no s u ch declarati on s yntax h as recei v ed ov erwh elm i ng s u p p ort.

W e s h ou ld als o note an addi ti onal tech ni cal wri nk le i n th i s i s s u e. C ons i der th e followi ng tem p late declarati ons , and let' s as s u m e th at th e lang u ag e h as been ex tended to accep t s tri ng li terals as tem p late arg u m ents i n th i s cas e:

template <char const* str> class Bracket { public:

Page 256: CPlusPlus Templates The Complete Guide

static char const* address() const; static char const* bytes() const; }; template <char const* str> char const* Bracket<T>::address() const { return str; } template <char const* str> char const* Bracket<T>::bytes() const { return str; }

I n th e p rev i ou s code, th e two m em ber fu ncti ons are i denti cal ex cep t for th ei r nam es —a s i tu ati on th at i s not th at u ncom m on. I m ag i ne th at an i m p lem entati on wou ld i ns tanti ate Bracket<"X"> u s i ng a p roces s m u ch li k e m acro ex p ans i on: I n th i s cas e, i f th e two m em ber fu ncti ons are i ns tanti ated i n di fferent trans lati on u ni ts , th ey m ay retu rn di fferent v alu es . I nteres ti ng ly, a tes t of s om e C + + com p i lers th at cu rrently p rov i de th i s ex tens i on rev eals th at th ey do s u ffer from th i s s u rp ri s i ng beh av i or.

A related i s s u e i s th e abi li ty to p rov i de floati ng -p oi nt li terals (and s i m p le cons tant floati ng -p oi nt ex p res s i ons ) as tem p late arg u m ents . F or ex am p le:

template <double Ratio> class Converter { public: static double convert (double val) const { return val*Ratio; } }; typedef Converter<0.0254> InchToMeter;

T h i s too i s p rov i ded by s om e C + + i m p lem entati ons and p res ents no s eri ou s tech ni cal ch alleng es (u nli k e th e s tri ng li teral arg u m ents ).

Page 257: CPlusPlus Templates The Complete Guide

13.5 Relaxed Matching of Template Template Parameters

A tem p late u s ed to s u bs ti tu te a tem p late tem p late p aram eter m u s t m atch th at p aram eter' s li s t of tem p late p aram eters ex actly. T h i s can s om eti m es h av e s u rp ri s i ng cons eq u ences , as s h own i n th e followi ng ex am p le:

#include <list> // declares: // namespace std { // template <typename T, // typename Allocator = allocator<T> > // class list; // } template<typename T1, typename T2, template<typename> class Container> // Container expects templates with only one parameter class Relation { public: … private: Container<T1> dom1; Container<T2> dom2; }; int main() { Relation<int, double, std::list> rel; // ERROR: std::list has more than one template parameter … }

T h i s p rog ram i s i nv ali d becau s e ou r tem p late tem p late p aram eter Container ex p ects a tem p late tak i ng one p aram eter, wh ereas std::list h as an allocator p aram eter i n addi ti on to i ts p aram eter th at determ i nes th e elem ent typ e.

H owev er, becau s e std::list h as a defau lt tem p late arg u m ent for i ts allocator p aram eter, i t wou ld be p os s i ble to s p eci fy th at Container m atch es std::list and th at each i ns tanti ati on of Container u s es th e defau lt tem p late arg u m ent of std::list (s ee Secti on 8 .3 .4 on p ag e 112).

A n arg u m ent i n fav or of th e statu s q u o (no m atch ) i s th at th e s am e ru le ap p li es to m atch i ng fu ncti on typ es . H owev er, i n th i s cas e th e defau lt arg u m ents cannot always be determ i ned becau s e th e v alu e of a fu ncti on p oi nter u s u ally i s n' t fi x ed u nti l ru n ti m e. I n contras t, th ere are no " tem p late p oi nters , " and all th e req u i red

Page 258: CPlusPlus Templates The Complete Guide

i nform ati on can be av ai lable at com p i le ti m e.

Som e C + + com p i lers already offer th e relax ed m atch i ng ru le as an ex tens i on. T h i s i s s u e i s als o related to th e i s s u e of typ edef tem p lates (di s cu s s ed i n th e nex t s ecti on). I ndeed, cons i der rep laci ng th e defi ni ti on of main() i n ou r p rev i ou s ex am p le wi th :

template <typename T> typedef list<T> MyList; int main() { Relation<int, double, MyList> rel; }

T h e typ edef tem p late i ntrodu ces a new tem p late th at now ex actly m atch es Container wi th res p ect to i ts p aram eter li s t. W h eth er th i s s treng th ens or weak ens th e cas e for a relax ed m atch i ng ru le i s , of cou rs e, arg u able.

T h i s i s s u e h as been brou g h t u p before th e C + + s tandardi z ati on com m i ttee, wh i ch i s cu rrently not i ncli ned to add th e relax ed m atch i ng ru le.

Page 259: CPlusPlus Templates The Complete Guide

13.6 Typedef Templates

C las s tem p lates are often com bi ned i n relati v ely s op h i s ti cated ways to obtai n oth er p aram eteri z ed typ es . W h en s u ch p aram eteri z ed typ es ap p ear rep eatedly i n s ou rce code, i t i s natu ral to want a s h ortcu t for th em , j u s t as typ edefs p rov i de a s h ortcu t for u np aram eteri z ed typ es .

T h erefore, C + + lang u ag e des i g ners are cons i deri ng a cons tru ct th at m ay look as follows :

template <typename T> typedef vector<list<T> > Table;

A fter th i s declarati on, Table wou ld be a new tem p late th at can be i ns tanti ated to becom e a concrete typ e defi ni ti on. Su ch a tem p late i s called a ty ped ef template (as op p os ed to a clas s tem p late or a fu ncti on tem p late). F or ex am p le:

Table<int> t; // t has type vector<list<int> >

C u rrently, th e lack of typ edef tem p lates i s work ed arou nd by u s i ng m em ber typ edefs of clas s tem p lates . F or ou r ex am p le we m i g h t u s e:

template <typename T> class Table { public: typedef vector<list<T> > Type; }; Table<int>::Type t; // t has type vector<list<int> >

B ecau s e typ edef tem p lates are to be fu ll-fledg ed tem p lates , th ey cou ld be s p eci ali z ed m u ch li k e clas s tem p lates :

// primary typedef template: template<typename T> typedef T Opaque; // partial specialization: template<typename T> typedef void* Opaque<T*>; // full specialization: template<> typedef bool Opaque<void>;

T yp edef tem p lates are not enti rely s trai g h tforward. F or ex am p le, i t i s not clear

Page 260: CPlusPlus Templates The Complete Guide

h ow th ey wou ld p arti ci p ate i n th e dedu cti on p roces s :

void candidate(long); template<typename T> typedef T DT; template<typename T> void candidate(DT<T>); int main() { candidate(42); // which candidate() should be called? }

I t i s not clear th at dedu cti on s h ou ld s u cceed i n th i s cas e. C ertai nly, dedu cti on i s not p os s i ble wi th arbi trary typ edef p atterns .

Page 261: CPlusPlus Templates The Complete Guide

13.7 Partial Specialization of Function Templates

I n C h ap ter 12 we di s cu s s ed h ow clas s tem p lates can be p arti ally s p eci ali z ed, wh ereas fu ncti on tem p lates are s i m p ly ov erloaded. T h e two m ech ani s m s are s om ewh at di fferent.

P arti al s p eci ali z ati on does n' t i ntrodu ce a com p letely new tem p late: I t i s an ex tens i on of an ex i s ti ng tem p late (th e pr i mar y tem p late). W h en a clas s tem p late i s look ed u p , only p ri m ary tem p lates are cons i dered at fi rs t. I f, after th e s electi on of a p ri m ary tem p late, i t tu rns ou t th at th ere i s a p arti al s p eci ali z ati on of th at tem p late wi th a tem p late arg u m ent p attern th at m atch es th at of th e i ns tanti ati on, i ts defi ni ti on (i n oth er words , i ts b od y ) i s i ns tanti ated i ns tead of th e defi ni ti on of th e p ri m ary tem p late. (F u ll tem p late s p eci ali z ati ons work ex actly th e s am e way.)

I n contras t, ov erloaded fu ncti on tem p lates are s ep arate tem p lates th at are com p letely i ndep endent of one anoth er. W h en s electi ng wh i ch tem p late to i ns tanti ate, all th e ov erloaded tem p lates are cons i dered tog eth er, and ov erload res olu ti on attem p ts to ch oos e one as th e bes t fi t. A t fi rs t th i s m i g h t s eem li k e an adeq u ate alternati v e, bu t i n p racti ce th ere are a nu m ber of li m i tati ons :

• I t i s p os s i ble to s p eci ali z e m em ber tem p lates of a clas s wi th ou t ch ang i ng th e defi ni ti on of th at clas s . H owev er, addi ng an ov erloaded m em ber does req u i re a ch ang e i n th e defi ni ti on of a clas s . I n m any cas es th i s i s not an op ti on becau s e we m ay not own th e ri g h ts to do s o. F u rth erm ore, th e C + + s tandard does not cu rrently allow u s to add new tem p lates to th e std nam es p ace, bu t i t does allow u s to s p eci ali z e tem p lates from th at nam es p ace.

• T o ov erload fu ncti on tem p lates , th ei r fu ncti on p aram eters m u s t di ffer i n s om e m ateri al way. C ons i der a fu ncti on tem p late R convert(T const&) wh ere R and T are tem p late p aram eters . W e m ay v ery well want to s p eci ali z e th i s tem p late for R = void, bu t th i s cannot be done u s i ng ov erloadi ng .

• C ode th at i s v ali d for a nonov erloaded fu ncti on m ay no long er be v ali d wh en th e fu ncti on i s ov erloaded. Sp eci fi cally, g i v en two fu ncti on tem p lates f(T) and g(T) (wh ere T i s a tem p late p aram eter), th e ex p res s i on g(&f<int>) i s v ali d only i f f i s not ov erloaded (oth erwi s e, th ere i s no way to deci de wh i ch f i s m eant).

• F ri end declarati ons refer to a s p eci fi c fu ncti on tem p late or an i ns tanti ati on of a s p eci fi c fu ncti on tem p late. A n ov erloaded v ers i on of a fu ncti on tem p late wou ld not au tom ati cally h av e th e p ri v i leg es g ranted to th e

Page 262: CPlusPlus Templates The Complete Guide

ori g i nal tem p late.

T og eth er, th i s li s t form s a com p elli ng arg u m ent i n s u p p ort of a p arti al s p eci ali z ati on cons tru ct for fu ncti on tem p lates .

A natu ral s yntax for p arti ally s p eci ali z i ng fu ncti on tem p lates i s th e g enerali z ati on of th e clas s tem p late notati on:

template <typename T> T const& max (T const&, T const&); // primary template template <typename T> T* const& max <T*>(T* const&, T* const&); // partial specialization

Som e lang u ag e des i g ners worry abou t th e i nteracti on of th i s p arti al s p eci ali z ati on ap p roach wi th fu ncti on tem p late ov erloadi ng . F or ex am p le:

template <typename T> void add (T& x, int i); // a primary template template <typename T1, typename T2> void add (T1 a, T2 b); // another (overloaded) primary template template <typename T> void add<T*> (T*&, int); // which primary template does this specialize?

H owev er, we ex p ect s u ch cas es wou ld be deem ed errors wi th ou t m aj or i m p act on th e u ti li ty of th e featu re.

A t th e ti m e of th i s wri ti ng , th i s ex tens i on i s u nder cons i derati on by th e C + + s tandardi z ati on com m i ttee.

Page 263: CPlusPlus Templates The Complete Guide

13.8 The typeof Operator

W h en wri ti ng tem p lates , i t i s often u s efu l to be able to ex p res s th e typ e of a tem p late-dep endent ex p res s i on. P erh ap s th e p os ter ch i ld of th i s s i tu ati on i s th e declarati on of an ari th m eti c op erator for a nu m eri c array tem p late i n wh i ch th e elem ent typ es of th e op erands are m i x ed. T h e followi ng ex am p le s h ou ld m ak e th i s clear:

template <typename T1, typename T2> Array<???> operator+ (Array<T1> const& x, Array<T2> const& y);

P res u m ably, th i s op erator i s to p rodu ce an array of elem ents th at are th e res u lt of addi ng corres p ondi ng elem ents i n th e arrays x and y. T h e typ e of a res u lti ng elem ent i s th u s th e typ e of x[0]+y[0]. U nfortu nately, C + + does not offer a reli able way to ex p res s th i s typ e i n term s of T1 and T2.

Som e com p i lers p rov i de th e typeof op erator as an ex tens i on th at addres s es th i s i s s u e. I t i s rem i ni s cent of th e sizeof op erator i n th at i t can tak e an ex p res s i on and p rodu ce a com p i le-ti m e enti ty from i t, bu t i n th i s cas e th e com p i le-ti m e enti ty can act as th e nam e of a typ e. I n ou r p rev i ou s ex am p le th i s allows u s to wri te:

template <typename T1, typename T2> Array<typeof(T1()+T2())> operator+ (Array<T1> const& x, Array<T2> const& y);

T h i s i s ni ce, bu t not i deal. I ndeed, i t as s u m es th at th e g i v en typ es can be defau lt-i ni ti ali z ed. W e can work arou nd th i s as s u m p ti on by i ntrodu ci ng a h elp er tem p late as follows :

template <typename T> T makeT(); // no definition needed template <typename T1, typename T2> Array<typeof(makeT<T1>()+makeT<T2>())> operator+ (Array<T1> const& x, Array<T2> const& y);

W e really wou ld p refer to u s e x and y i n th e typeof arg u m ent, bu t we cannot do s o becau s e th ey h av e not been declared at th e p oi nt of th e typeof cons tru ct. A radi cal s olu ti on to th i s p roblem i s to i ntrodu ce an alternati v e fu ncti on declarati on s yntax th at p laces th e retu rn typ e af ter th e p aram eter typ es :

Page 264: CPlusPlus Templates The Complete Guide

// operator function template: template <typename T1, typename T2> operator+ (Array<T1> const& x, Array<T2> const& y) -> Array<typeof(x+y)>; // regular function template: template <typename T1, typename T2> function exp(Array<T1> const& x, Array<T2> const& y) -> Array<typeof(exp(x, y))>

A s th e ex am p le i llu s trates , a new k eyword (h ere, function) i s neces s ary to enable th e new s yntax for nonop erator fu ncti ons (for op erator fu ncti ons , th e operator k eyword i s s u ffi ci ent to g u i de th e p ars i ng p roces s ).

N ote th at typeof m u s t be a com p i le-ti m e op erator. I n p arti cu lar, typeof wi ll not tak e i nto accou nt cov ari ant retu rn typ es , as th e followi ng ex am p le s h ows :

class Base { public: virtual Base clone(); }; class Derived : public Base { public: virtual Derived clone(); // covariant return type }; void demo (Base* p, Base* q) { typeof(p->clone()) tmp = p->clone(); // tmp will always have type Base … }

Secti on 15 .2.4 on p ag e 27 1 s h ows h ow p rom oti on trai ts are s om eti m es u s ed to p arti ally addres s th e abs ence of a typeof op erator.

Page 265: CPlusPlus Templates The Complete Guide

13.9 Named Template Arguments

Secti on 16.1 on p ag e 28 5 des cri bes a tech ni q u e th at allows u s to p rov i de a nondefau lt tem p late arg u m ent for a s p eci fi c p aram eter wi th ou t h av i ng to s p eci fy oth er tem p late arg u m ents for wh i ch a defau lt v alu e i s av ai lable. A lth ou g h i t i s an i nteres ti ng tech ni q u e, i t i s als o clear th at i t res u lts i n a fai r am ou nt of work for a relati v ely s i m p le effect. H ence, p rov i di ng a lang u ag e m ech ani s m to nam e tem p late arg u m ents i s a natu ral th ou g h t.

W e s h ou ld note at th i s p oi nt, th at a s i m i lar ex tens i on (s om eti m es called k ey w or d ar g u men ts) was p rop os ed earli er i n th e C + + s tandardi z ati on p roces s by R oland H arti ng er (s ee Secti on 6.5 .1 of [Strou s tru p D nE ] ). A lth ou g h tech ni cally s ou nd, th e p rop os al was u lti m ately not accep ted i nto th e lang u ag e for v ari ou s reas ons . A t th i s p oi nt th ere i s no reas on to beli ev e nam ed tem p late arg u m ents wi ll ev er m ak e i t i nto th e lang u ag e.

H owev er, for th e s ak e of com p letenes s , we m enti on one s yntacti c i dea th at h as floated am ong certai n des i g ners :

template<typename T, Move: typename M = defaultMove<T>, Copy: typename C = defaultCopy<T>, Swap: typename S = defaultSwap<T>, Init: typename I = defaultInit<T>, Kill: typename K = defaultKill<T> > class Mutator { … }; void test(MatrixList ml) { mySort (ml, Mutator <Matrix, Swap: matrixSwap>); }

N ote h ow th e arg u m ent nam e (p recedi ng a colon) i s di s ti nct from th e p aram eter nam e. T h i s allows u s to k eep th e p racti ce of u s i ng s h ort nam es for th e p aram eters u s ed i n th e i m p lem entati on wh i le h av i ng a s elf-docu m enti ng nam e for th e arg u m ent nam es . B ecau s e th i s can be ov erly v erbos e for s om e p rog ram m i ng s tyles , one can als o i m ag i ne th e abi li ty to om i t th e arg u m ent nam e i f i t i s i denti cal to th e p aram eter nam e:

template<typename T, : typename Move = defaultMove<T>, : typename Copy = defaultCopy<T>, : typename Swap = defaultSwap<T>, : typename Init = defaultInit<T>,

Page 266: CPlusPlus Templates The Complete Guide

: typename Kill = defaultKill<T> > class Mutator { … };

Page 267: CPlusPlus Templates The Complete Guide

13.10 Static Properties

I n C h ap ter 15 and C h ap ter 19 we di s cu s s v ari ou s ways to categ ori z e typ es " at com p i le ti m e." Su ch trai ts are u s efu l i n s electi ng s p eci ali z ati ons of tem p lates bas ed on th e s tati c p rop erti es of th e typ e. (See, for ex am p le, ou r CSMtraits clas s i n Secti on 15 .3 .2 on p ag e 27 9 , wh i ch attem p ts to s elect op ti m al or near-op ti m al p oli ci es to cop y, s wap , or m ov e elem ents of th e arg u m ent typ e.)

Som e lang u ag e des i g ners h av e obs erv ed th at i f s u ch " s p eci ali z ati on s electi ons " are com m onp lace, th ey s h ou ldn' t req u i re elaborate u s er-defi ned code i f all th at i s s ou g h t i s a p rop erty th at th e i m p lem entati on k nows i nternally anyway. T h e lang u ag e cou ld i ns tead p rov i de a nu m ber of bu i lt-i n typ e trai ts . T h e followi ng cou ld be a v ali d com p lete C + + p rog ram wi th s u ch an ex tens i on:

#include <iostream> int main() { std::cout << std::type<int>::is_bit_copyable << '\n'; std::cout << std::type<int>::is_union << '\n'; }

A lth ou g h a s ep arate s yntax cou ld be dev elop ed for s u ch a cons tru ct, fi tti ng i t i n a u s er-defi nable s yntax m ay allow for a m ore s m ooth trans i ti on from th e cu rrent lang u ag e to a lang u ag e th at wou ld i nclu de s u ch faci li ti es . H owev er, s om e of th e s tati c p rop erti es th at a C + + com p i ler can eas i ly p rov i de m ay not be obtai nable u s i ng tradi ti onal trai ts tech ni q u es (for ex am p le, determ i ni ng wh eth er a typ e i s a u ni on), wh i ch i s an arg u m ent i n fav or of m ak i ng th i s a lang u ag e elem ent. A noth er arg u m ent i s th at i t can s i g ni fi cantly redu ce th e am ou nt of m em ory and m ach i ne cycles req u i red by a com p i ler to trans late p rog ram s th at rely on s u ch p rop erti es .

Page 268: CPlusPlus Templates The Complete Guide

13.11 Custom Instantiation Diagnostics

M any tem p lates p u t s om e i m p li ci t req u i rem ents on th ei r p aram eters . W h en th e arg u m ents of an i ns tanti ati on of s u ch a tem p late do not fu lfi ll th e req u i rem ents , ei th er a g eneri c error i s i s s u ed or th e g enerated i ns tanti ati on does not fu ncti on correctly. I n early C + + com p i lers , th e g eneri c errors p rodu ced du ri ng tem p late i ns tanti ati ons were often ex ceedi ng ly op aq u e (s ee p ag e 7 5 for an ex am p le). I n m ore recent com p i lers , th e error m es s ag es are s u ffi ci ently clear for an ex p eri enced p rog ram m er to track down a p roblem q u i ck ly, bu t th ere i s s ti ll a des i re to i m p rov e th e s i tu ati on. C ons i der th e followi ng arti fi ci al ex am p le (m eant to i llu s trate wh at h ap p ens i n real tem p late li brari es ):

template <typename T> void clear (T const& p) { *p = 0; // assumes T is a pointerlike type } template <typename T> void core (T const& p) { clear(p); } template <typename T> void middle (typename T::Index p) { core(p); } template <typename T> void shell (T const& env) { typename T::Index i; middle<T>(i); } class Client { public: typedef int Index; … }; Client main_client; int main() { shell(main_client); }

T h i s ex am p le i llu s trates th e typ i cal layeri ng of s oftware dev elop m ent: H i g h -lev el

Page 269: CPlusPlus Templates The Complete Guide

fu ncti on tem p lates li k e shell() rely on com p onents li k e middle(), wh i ch th em s elv es m ak e u s e of bas i c faci li ti es li k e core(). W h en we i ns tanti ate shell(), all th e layers below i t als o need to be i ns tanti ated. I n th i s ex am p le, a p roblem i s rev ealed i n th e deep es t layer: core() i s i ns tanti ated wi th typ e int (from th e u s e of Client::Index i n middle()) and attem p ts to dereference a v alu e of th at typ e, wh i ch i s an error. A g ood g eneri c di ag nos ti c wi ll i nclu de a trace of all th e layers th at led to th e p roblem s , bu t th i s am ou nt of i nform ati on m ay be u nwi eldy.

A n alternati v e th at h as often been p rop os ed i s to i ns ert a dev i ce i n th e h i g h es t lev el tem p late to i nh i bi t deep er i ns tanti ati on i f k nown req u i rem ents from lower lev els are not s ati s fi ed. V ari ou s attem p ts h av e been m ade to i m p lem ent s u ch dev i ces i n term s of ex i s ti ng C + + cons tru cts (for ex am p le, s ee [B C C L ] ), bu t th ey are not always effecti v e. H ence, i t i s not s u rp ri s i ng th at lang u ag e ex tens i ons h av e been p rop os ed to addres s th e i s s u e. Su ch an ex tens i on cou ld clearly bu i ld on top of th e s tati c p rop erti es faci li ti es di s cu s s ed earli er. F or ex am p le, we can env i s i on m odi fyi ng th e shell() tem p late as follows :

template <typename T> void shell (T const& env) { std::instantiation_error( std::type<T>::has_member_type<"Index">, "T must have an Index member type"); std::instantiation_error( !std::type<typename T::Index>::dereferencable, "T::Index must be a pointer-like type"); typename T::Index i; middle(i); }

T h e instantiation_error() p s eu do-fu ncti on wou ld p res u m ably cau s e th e i m p lem entati on to abort th e i ns tanti ati on (th ereby av oi di ng th e di ag nos ti cs tri g g ered by th e i ns tanti ati on of middle()) and cau s e th e com p i ler to i s s u e th e g i v en m es s ag e.

A lth ou g h th i s i s feas i ble, th ere are s om e drawback s to th i s ap p roach . F or ex am p le, i t can q u i ck ly becom e cu m bers om e to des cri be all th e p rop erti es of a typ e i n th i s m anner. Som e h av e p rop os ed to allow " du m m y code" cons tru cts to s erv e as th e condi ti on to abort i ns tanti ati on. H ere i s one of th e m any p rop os ed form s (th i s one i ntrodu ces no new k eywords ):

template <typename T> void shell (T const& env) { template try { typename T::Index p;

Page 270: CPlusPlus Templates The Complete Guide

*p = 0; } catch "T::Index must be a pointer-like type"; typename T::Index i; middle(i); }

T h e i dea h ere i s th at th e body of a template try clau s e i s tentati v ely i ns tanti ated wi th ou t actu ally g enerati ng obj ect code, and, i f an error occu rs , th e di ag nos ti c th at follows i s i s s u ed. U nfortu nately, s u ch a m ech ani s m i s h ard to i m p lem ent becau s e ev en th ou g h th e g enerati on of code cou ld be i nh i b-i ted, th ere are oth er s i de effects i nternal to a com p i ler th at are h ard to av oi d. I n oth er words , th i s relati v ely s m all featu re wou ld li k ely req u i re a cons i derable reeng i neeri ng of ex i s ti ng com p i lati on tech nolog y.

M os t s u ch s ch em es als o h av e oth er li m i tati ons . F or ex am p le, m any C + + com p i lers can rep ort di ag nos ti cs i n di fferent lang u ag es (E ng li s h , G erm an, J ap anes e, and s o forth ), bu t p rov i di ng v ari ou s trans lati ons i n th e s ou rce code cou ld p rov e ex ces s i v e. F u rth erm ore, i f th e i ns tanti ati on p roces s i s tru ly aborted and th e p recondi ti on was not p reci s ely form u lated, a p rog ram m er m i g h t be m u ch wors e off th an wi th a g eneri c (albei t u nwi eldy) di ag nos ti c.

Page 271: CPlusPlus Templates The Complete Guide

13.12 Overloaded Class Templates

I t i s enti rely p os s i ble to i m ag i ne th at clas s tem p lates cou ld be ov erloaded on th ei r tem p late p aram eters . F or ex am p le, one can i m ag i ne th e followi ng :

template <typename T1> class Tuple { // singleton … }; template <typename T1, typename T2> class Tuple { // pair … }; template <typename T1, typename T2, typename T3> class Tuple { // three-element tuple … };

I n th e nex t s ecti on we di s cu s s an ap p li cati on of s u ch ov erloadi ng .

T h e ov erloadi ng i s n' t neces s ari ly res tri cted to th e nu m ber of tem p late p aram eters (s u ch ov erloadi ng cou ld be em u lated u s i ng p arti al s p eci ali z ati on as i s done for FunctionPtr i n C h ap ter 22). T h e k i n d of p aram eters can be v ari ed too:

template <typename T1, typename T2> class Pair { // pair of fields … }; template <int I1, int I2> class Pair { // pair of constant integer values … };

A lth ou g h th i s i dea h as been di s cu s s ed i nform ally by s om e lang u ag e des i g ners , i t h as not yet been form ally p res ented to th e C + + s tandardi z ati on com m i ttee.

Page 272: CPlusPlus Templates The Complete Guide

13.13 List Parameters

A need th at s h ows u p s om eti m es i s th e abi li ty to p as s a li s t of typ es as a s i ng le tem p late arg u m ent. U s u ally, th i s li s t i s m eant for one of two p u rp os es : declari ng a fu ncti on wi th a p aram eteri z ed nu m ber of p aram eters or defi ni ng a typ e s tru ctu re wi th a p aram eteri z ed li s t of m em bers .

F or ex am p le, we m ay want to defi ne a tem p late th at com p u tes th e m ax i m u m of an arbi trary li s t of v alu es . A p otenti al declarati on s yntax u s es th e elli p s i s tok en to denote th at th e las t tem p late p aram eter i s m eant to m atch an arbi trary nu m ber of arg u m ents :

#include <iostream> template <typename T, ... list> T const& max (T const&, T const&, list const&); int main() { std::cout << max(1, 2, 3, 4) << std::endl; }

V ari ou s p os s i bi li ti es can be th ou g h t of to i m p lem ent s u ch a tem p late. H ere i s one th at does n' t req u i re new k eywords bu t adds a ru le to fu ncti on tem p late ov erloadi ng to p refer a fu ncti on tem p late wi th ou t a li s t p aram eter:

template <typename T> inline T const& max (T const& a, T const& b) { // our usual binary maximum: return a<b?b:a; } template <typename T, ... list> inline T const& max (T const& a, T const& b, list const& x) { return max (a, max(b,x)); }

L et' s g o th rou g h th e s tep s th at wou ld m ak e th i s work for th e call max(1, 2, 3, 4). B ecau s e th ere are fou r arg u m ents , th e bi nary max() fu ncti on does n' t m atch , bu t th e s econd one does m atch wi th T = int and list = int, int. T h i s cau s es u s to call th e bi nary fu ncti on tem p late max() wi th th e fi rs t arg u m ent eq u al to 1 and th e s econd arg u m ent eq u al to th e ev alu ati on of max(2, 3, 4). A g ai n, th e bi nary op erati on does n' t m atch , and we call th e li s t p aram eter v ers i on wi th T = int and list = int. T h i s ti m e th e s u bex p res s i on max(b,x) ex p ands

Page 273: CPlusPlus Templates The Complete Guide

to max(3,4) , and th e recu rs i on ends by s electi ng th e bi nary tem p late.

T h i s work s fai rly well th ank s to th e abi li ty of ov erloadi ng fu ncti on tem p lates . T h ere i s m ore to i t th an ou r di s cu s s i on, of cou rs e. F or ex am p le, we' d h av e to s p eci fy p reci s ely wh at list const& m eans i n th i s contex t.

Som eti m es , i t m ay be des i rable to refer to p arti cu lar elem ents or s u bs ets of th e li s t. F or ex am p le, we cou ld u s e th e s u bs cri p t brack ets for th i s p u rp os e. T h e followi ng ex am p le s h ows h ow we cou ld cons tru ct a m etap rog ram to cou nt th e elem ents i n a li s t u s i ng th i s tech ni q u e:

template <typename T> class ListProps { public: enum { length = 1 }; }; template <... list> class ListProps { public: enum { length = 1+ListProps<list[1 ...]>::length }; };

T h i s dem ons trates th at li s t p aram eters m ay als o be u s efu l for clas s tem p lates and cou ld be com bi ned wi th th e clas s ov erloadi ng concep t di s cu s s ed earli er to enh ance v ari ou s tem p late m etap rog ram m i ng tech ni q u es .

A lternati v ely, th e li s t p aram eter cou ld be u s ed to declare a li s t of fi elds :

template <... list> class Collection { list; };

A s u rp ri s i ng nu m ber of fu ndam ental u ti li ti es can be bu i lt on top of s u ch a faci li ty. F or m ore i deas , we s u g g es t readi ng M od er n C++ D esi g n (s ee [A lex andres cu D es i g n] ), wh ere th e lack of th i s featu re i s rep laced by ex tens i v e tem p late- and m acro-bas ed m etap rog ram m i ng .

Page 274: CPlusPlus Templates The Complete Guide

13.14 Layout Control

A fai rly com m on tem p late p rog ram m i ng ch alleng e i s to declare an array of bytes th at wi ll be s u ffi ci ently larg e (bu t not ex ces s i v ely s o) to h old an obj ect of an as yet u nk nown typ e T—i n oth er words , a tem p late p aram eter. O ne ap p li cati on of th i s i s th e s o-called d i sc r i mi n ated u n i on s (als o called v ar i an t ty pes or tag g ed u n i on s):

template <... list> class D_Union { public: enum { n_bytes; }; char bytes[n_bytes]; // will eventually hold one of various types // described by the template arguments … };

T h e cons tant n_bytes cannot always be s et to sizeof(T) becau s e T m ay h av e m ore s tri ct ali g nm ent req u i rem ents th an th e bytes bu ffer. V ari ou s h eu ri s ti cs ex i s t to tak e th i s ali g nm ent i nto accou nt, bu t th ey are often com p li cated or m ak e s om ewh at arbi trary as s u m p ti ons .

F or s u ch an ap p li cati on, wh at i s really des i red i s th e abi li ty to ex p res s th e ali g nm ent req u i rem ent of a typ e as a cons tant ex p res s i on and, conv ers ely, th e abi li ty to i m p os e an ali g nm ent on a typ e, a fi eld, or a v ari able. M any C and C + + com p i lers already s u p p ort an __alignof__ op erator, wh i ch retu rns th e ali g nm ent of a g i v en typ e or ex p res s i on. T h i s i s alm os t i denti cal to th e sizeof op erator ex cep t th at th e ali g nm ent i s retu rned i ns tead of th e s i z e of th e g i v en typ e. M any com p i lers als o p rov i de #pragma di recti v es or s i m i lar dev i ces to s et th e ali g nm ent of an enti ty. A p os s i ble ap p roach m ay be to i ntrodu ce an alignof k eyword th at can be u s ed both i n ex p res s i ons (to obtai n th e ali g nm ent) and i n declarati ons (to s et th e ali g nm ent).

template <typename T> class Alignment { public: enum { max = alignof(T) }; }; template <... list> class Alignment { public: enum { max = alignof(list[0]) > Alignment<list[1 ...]>::max ? alignof(list[0]) : Alignment<list[1 ...]>::max; }

Page 275: CPlusPlus Templates The Complete Guide

}; // a set of Size templates could similarly be designed // to determine the largest size among a given list of types template <... list> class Variant { public: char buffer[Size<list>::max] alignof(Alignment<list>::max); … };

Page 276: CPlusPlus Templates The Complete Guide

13.15 Initializer Deduction

I t i s often s ai d th at " p rog ram m ers are laz y, " and s om eti m es th i s refers to ou r des i re to k eep p rog ram m ati c notati on com p act. C ons i der, i n th at res p ect, th e followi ng declarati on:

std::map<std::string, std::list<int> >* dict = new std::map<std::string, std::list<int> >;

T h i s i s v erbos e, and i n p racti ce we wou ld (and m os t li k ely s h ou ld) i ntrodu ce a typedef s ynonym for th e typ e. H owev er, th ere i s s om eth i ng redu ndant i n th i s declarati on: W e s p eci fy th e typ e of dict , bu t i t i s als o i m p li ci t i n th e typ e of i ts i ni ti ali z er. W ou ldn' t i t be cons i derably m ore eleg ant to be able to wri te an eq u i v alent declarati on wi th only one typ e s p eci fi cati on? F or ex am p le:

dcl dict = new std::map<std::string, std::list<int> >;

I n th i s las t declarati on, th e typ e of a v ari able i s dedu ced from th e typ e of th e i ni ti ali z er. A k eyword (dcl i n th e ex am p le, bu t var, let , and ev en auto h av e been p rop os ed as alternati v es ) i s needed to m ak e th e declarati on di s ti ng u i s h able from an ordi nary as s i g nm ent.

So far, th i s i s n' t a tem p late-only i s s u e. I n fact, i t ap p ears s u ch a cons tru ct was accep ted by a v ery early v ers i on of th e C front com p i ler (i n 19 8 2, before tem p lates cam e on th e s cene). H owev er, i t i s th e v erbos i ty of m any tem p late-bas ed typ es th at i ncreas es th e dem and for th i s featu re.

O ne cou ld als o i m ag i ne p arti al dedu cti on i n wh i ch only th e arg u m ents of a tem p late m u s t be dedu ced:

std::list<> index = create_index();

A noth er v ari ant of th i s i s to dedu ce th e tem p late arg u m ents from th e cons tru ctor arg u m ents . F or ex am p le:

template <typename T> class Complex { public: Complex(T const& re, T const& im); … };

Page 277: CPlusPlus Templates The Complete Guide

Complex<> z(1.0, 3.0); // deduces T = double

P reci s e s p eci fi cati ons for th i s k i nd of dedu cti on are m ade m ore com p li cated by th e p os s i bi li ty of ov erloaded cons tru ctors , i nclu di ng cons tru ctor tem p lates . Su p p os e, for ex am p le, th at ou r Complex tem p late contai ns a cons tru ctor tem p late i n addi ti on to a norm al cop y cons tru ctor:

template <typename T> class Complex { public: Complex(Complex<T> const&); template <typename T2> Complex(Complex<T2> const&); … }; Complex<double> j(0.0, 1.0); Complex<> z = j; // Which constructor was intended?

I n th e latter i ni ti ali z ati on, i t i s p robable th at th e reg u lar cop y cons tru ctor was i ntended; h ence z s h ou ld h av e th e s am e typ e as j. H owev er, m ak i ng i t an i m p li ci t ru le to i g nore cons tru ctor tem p lates m ay be ov erly bold.

Page 278: CPlusPlus Templates The Complete Guide

13.16 Function Expressions

C h ap ter 22 i llu s trates th at i t i s often conv eni ent to p as s s m all fu ncti ons (or fu nctors ) as p aram eters to oth er fu ncti ons . W e als o m enti on i n C h ap ter 17 th at ex p res s i on tem p late tech ni q u es can be u s ed to bu i ld s m all fu nctors conci s ely wi th ou t th e ov erh ead of ex p li ci t declarati ons (s ee Secti on 18 .3 on p ag e 3 4 0).

F or ex am p le, we m ay want to call a p arti cu lar m em ber fu ncti on on each elem ent of a s tandard v ector to i ni ti ali z e i t:

class BigValue { public: void init(); … }; class Init { public: void operator() (BigValue& v) const { v.init(); } }; void compute (std::vector<BigValue>& vec) { std::for_each (vec.begin(), vec.end(), Init()); … }

T h e need to defi ne a s ep arate clas s Init for th i s p u rp os e i s u nwi eldy. I ns tead, we can i m ag i ne th at we m ay wri te (u nnam ed) fu ncti on bodi es as p art of an ex p res s i on:

class BigValue { public: void init(); … }; void compute (std::vector<BigValue>& vec) { std::for_each (vec.begin(), vec.end(), $(BigValue&) { $1.init(); }); … }

T h e i dea h ere i s th at we can i ntrodu ce a f u n c ti on ex pr essi on wi th a s p eci al tok en $ followed by p aram eter typ es i n p arenth es es and a brace-enclos ed body. W i th i n s u ch a cons tru ct, we can refer to th e p aram eters wi th th e s p eci al notati on $n,

Page 279: CPlusPlus Templates The Complete Guide

wh ere n i s a cons tant i ndi cati ng th e nu m ber of th e p aram eter.

T h i s form i s clos ely related to s o-called lamb d a ex pr essi on s (or lamb d a f u n c ti on s) and c losu r es i n oth er p rog ram m i ng lang u ag es . H owev er, oth er s olu ti ons are p os s i ble. F or ex am p le, a s olu ti on m i g h t u s e anonym ou s i nner clas s es , as s een i n J av a:

class BigValue { public: void init(); … }; void compute (std::vector<BigValue>& vec) { std::for_each (vec.begin(), vec.end(), class { public: void operator() (BigValue& v) const { v.init(); } }; ); … }

A lth ou g h th es e s orts of cons tru cts reg u larly com e u p am ong lang u ag e des i g ners , concrete p rop os als are rare. T h i s i s p robably a cons eq u ence of th e fact th at des i g ni ng s u ch an ex tens i on i s a cons i derable tas k th at am ou nts to m u ch m ore th an ou r ex am p les m ay s u g g es t. A m ong th e i s s u es to be tack led are th e s p eci fi cati on of th e retu rn typ e and th e ru les th at determ i ne wh at enti ti es are av ai lable wi th i n th e body of a fu ncti on ex p res s i on. F or ex am p le, can local v ari ables i n th e s u rrou ndi ng fu ncti on be acces s ed? F u ncti on ex p res s i ons cou ld als o concei v ably be tem p lates i n wh i ch th e typ es of th e p aram eters wou ld be dedu ced from th e u s e of th e fu ncti on ex p res s i on. Su ch an ap p roach m ay m ak e th e p rev i ou s ex am p le ev en m ore conci s e (by allowi ng u s to om i t th e p aram eter li s t altog eth er), bu t i t bri ng s wi th i t new ch alleng es for th e tem p late arg u m ent dedu cti on s ys tem .

I t i s not at all clear th at C + + wi ll ev er i nclu de a concep t li k e fu ncti on ex p res s i ons . H owev er, th e L amb d a L i b r ar y of J aak k o J ä rv i and G ary P owell (s ee [L am bdaL i b] ) g oes a long way toward p rov i di ng th e des i red fu ncti onali ty, albei t at a cons i derable p ri ce i n com p i ler res ou rces .

Page 280: CPlusPlus Templates The Complete Guide

13.17 Afternotes

I t s eem s p erh ap s p rem atu re to talk abou t ex tendi ng th e lang u ag e wh en C + + com p i lers are only barely becom i ng m os tly com p li ant to th e 19 9 8 s tandard (C + + 9 8 ). H owev er, i t i s i n p art becau s e th i s com p li ance i s bei ng ach i ev ed th at we (th e C + + p rog ram m ers com m u ni ty) are g ai ni ng i ns i g h t i nto th e tru e li m i tati ons of C + + (and tem p lates i n p arti cu lar).

T o m eet th e new needs of C + + p rog ram m ers , th e C + + s tandards com m i ttee (often referred to as I SO W G 21/A N SI J 16, or j u s t W G 21/J 16) s tarted ex am i ni ng a road to a new s tandard: C + + 0x . A fter a p reli m i nary p res entati on at i ts A p ri l 2001 m eeti ng i n C op enh ag en, W G 21/J 16 s tarted ex am i ni ng concrete li brary ex tens i on p rop os als .

I ndeed, th e i ntenti on i s to attem p t as m u ch as p os s i ble to confi ne ex tens i ons to th e C + + s tandard li brary. H owev er, i t i s well u nders tood th at s om e of th es e ex tens i ons m ay req u i re work i n th e core lang u ag e. W e ex p ect th at m any of th es e req u i red m odi fi cati ons wi ll relate to C + + tem p lates , j u s t as th e i ntrodu cti on of ST L i n th e C + + s tandard li brary s ti m u lated tem p late tech nolog y i n th e 19 9 0s .

F i nally, C + + 0x i s als o ex p ected to addres s s om e " em barras s m ents " i n C + + 9 8 . I t i s h op ed th at doi ng s o wi ll i m p rov e th e acces s i bi li ty of C + + . Som e of th e ex tens i ons i n th at di recti on were di s cu s s ed i n th i s ch ap ter.

Page 281: CPlusPlus Templates The Complete Guide

Part III: Templates and Design

P rog ram s are g enerally cons tru cted u s i ng des i g ns th at m ap relati v ely well on th e m ech ani s m s offered by a ch os en p rog ram m i ng lang u ag e. B ecau s e tem p lates are a wh ole new lang u ag e m ech ani s m , i t i s not s u rp ri s i ng to fi nd th at th ey call for new des i g n elem ents . W e ex p lore th es e elem ents i n th i s p art of th e book .

T em p lates are di fferent from m ore tradi ti onal lang u ag e cons tru cts i n th at th ey allow u s to p aram eteri z e th e typ es and cons tants of ou r code. W h en com bi ned wi th (1) p arti al s p eci ali z ati on and (2) recu rs i v e i ns tanti ati on, th i s leads to a s u rp ri s i ng am ou nt of ex p res s i v e p ower. I n th e followi ng ch ap ters , th i s i s i llu s trated by a larg e nu m ber of des i g n tech ni q u es :

• G eneri c p rog ram m i ng • T rai ts • P oli cy clas s es • M etap rog ram m i ng • E x p res s i on tem p lates

O u r p res entati on ai m s not only at li s ti ng th e v ari ou s k nown des i g n elem ents , bu t als o at conv eyi ng th e p ri nci p les th at i ns p i re s u ch des i g ns s o th at new tech ni q u es m ay be created.

Page 282: CPlusPlus Templates The Complete Guide

Chapter 14. The Polymorphic Power of Templates

Poly mor phi sm i s th e abi li ty to as s oci ate di fferent s p eci fi c beh av i ors wi th a s i ng le g eneri c notati on. [1] P olym orp h i s m i s als o a corners tone of th e obj ect-ori ented p rog ram m i ng p aradi g m , wh i ch i n C + + i s s u p p orted m ai nly th rou g h clas s i nh eri tance and v i rtu al fu ncti ons . B ecau s e th es e m ech ani s m are (at leas t i n p art) h andled at ru n ti m e, we talk abou t d y n ami c poly mor phi sm. T h i s i s u s u ally wh at i s th ou g h t of wh en talk i ng abou t p lai n p olym orp h i s m i n C + + . H owev er, tem p lates als o allow u s to as s oci ate di fferent s p eci fi c beh av i ors wi th a s i ng le g eneri c notati on, bu t th i s as s oci ati on i s g enerally h andled at com p i le ti m e, wh i ch we refer to as stati c poly mor phi sm. I n th i s ch ap ter we rev i ew th e two form s of p olym orp h i s m and di s cu s s wh i ch form i s ap p rop ri ate i n wh i ch s i tu ati ons .

[1] Poly mor phi sm li terally refers to th e condi ti on of h av i ng m any form s or s h ap es (from th e G reek polu mor phos).

Page 283: CPlusPlus Templates The Complete Guide

14.1 Dynamic Polymorphism

H i s tori cally, C + + s tarted wi th s u p p orti ng p olym orp h i s m only th rou g h th e u s e of i nh eri tance com bi ned wi th v i rtu al fu ncti ons . [2 ] T h e art of p olym orp h i c des i g n i n th i s contex t cons i s ts of i denti fyi ng a com m on s et of cap abi li ti es am ong related obj ect typ es and declari ng th em as v i rtu al fu ncti on i nterfaces i n a com m on bas e clas s .

[2 ] Stri ctly s p eak i ng , m acros can als o be th ou g h t of as an early form of s tati c p olym orp h i s m . H owev er, th ey are left ou t of cons i derati on becau s e th ey are m os tly orth og onal to th e oth er lang u ag e m ech ani s m s .

T h e p os ter ch i ld for th i s des i g n ap p roach i s an ap p li cati on th at m anag es g eom etri c s h ap es and allows th em to be rendered i n s om e way (for ex am p le, on a s creen). I n s u ch an ap p li cati on we m i g h t i denti fy a s o-called ab str ac t b ase c lass (AB C) GeoObj , wh i ch declares th e com m on op erati ons and p rop erti es ap p li cable to g eom etri c obj ects . E ach concrete clas s for s p eci fi c g eom etri c obj ects th en deri v es from GeoObj (s ee F i g u re 14 .1):

Figure 14.1. Polymorphism implemented via inheritance

// poly/dynahier.hpp #include "coord.hpp" // common abstract base class GeoObj for geometric objects class GeoObj { public: // draw geometric object: virtual void draw() const = 0; // return center of gravity of geometric object: virtual Coord center_of_gravity() const = 0; … };

Page 284: CPlusPlus Templates The Complete Guide

// concrete geometric object class Circle // - derived from GeoObj class Circle : public GeoObj { public: virtual void draw() const; virtual Coord center_of_gravity() const; … }; // concrete geometric object class Line // - derived from GeoObj class Line : public GeoObj { public: virtual void draw() const; virtual Coord center_of_gravity() const; … }; …

A fter creati ng concrete obj ects , cli ent code can m ani p u late th es e obj ects th rou g h references or p oi nters to th e bas e clas s , wh i ch enables th e v i rtu al fu ncti on di s p atch m ech ani s m . C alli ng a v i rtu al m em ber fu ncti on th rou g h a p oi nter or reference to a bas e clas s s u bobj ect res u lts i n an i nv ocati on of th e ap p rop ri ate m em ber of th e s p eci fi c concrete obj ect to wh i ch was referred.

I n ou r ex am p le, th e concrete code can be s k etch ed as follows :

// poly/dynapoly.cpp #include "dynahier.hpp" #include <vector> // draw any GeoObj void myDraw (GeoObj const& obj) { obj.draw(); // call draw() according to type of object } // process distance of center of gravity between two GeoObjs Coord distance (GeoObj const& x1, GeoObj const& x2) { Coord c = x1.center_of_gravity() - x2.center_of_gravity(); return c.abs(); // return coordinates as absolute values } // draw inhomogeneous collection of GeoObjs void drawElems (std::vector<GeoObj*> const& elems) { for (unsigned i=0; i<elems.size(); ++i) { elems[i]->draw(); // call draw() according to type of element } } int main() { Line l;

Page 285: CPlusPlus Templates The Complete Guide

Circle c, c1, c2; myDraw(l); // myDraw(GeoObj&) => Line::draw() myDraw(c); // myDraw(GeoObj&) => Circle::draw() distance(c1,c2); // distance(GeoObj&,GeoObj&) distance(l,c); // distance(GeoObj&,GeoObj&) std::vector<GeoObj*> coll; // inhomogeneous collection coll.push_back(&l); // insert line coll.push_back(&c); // insert circle drawElems(coll); // draw different kinds of GeoObjs }

T h e k ey p olym orp h i c i nterface elem ents are th e fu ncti ons draw() and center_of_gravity(). B oth are v i rtu al m em ber fu ncti ons . O u r ex am p le dem ons trates th ei r u s e i n th e fu ncti ons mydraw(), distance() , anddrawElems(). T h e latter fu ncti ons are ex p res s ed u s i ng th e com m on bas e typ e GeoObj. A s a cons eq u ence i t cannot be determ i ned at com p i le ti m e wh i ch v ers i on of draw() or center_of_gravity() h as to be u s ed. H owev er, at ru n ti m e, th e com p lete dynam i c typ e of th e obj ects for wh i ch th e v i rtu al fu ncti ons are i nv ok ed i s acces s ed to di s p atch th e fu ncti on calls . H ence, dep endi ng on th e actu al typ e of a g eom etri c obj ect, th e ap p rop ri ate op erati on i s done: I f mydraw() i s called for a Line obj ect, th e ex p res s i on obj.draw() calls Line::draw(), wh ereas for a Circle obj ect th e fu ncti on Circle::draw() i s called. Si m i larly, wi th distance() th e m em ber fu ncti ons center_of_gravity() ap p rop ri ate for th e arg u m ent obj ects are called.

P erh ap s th e m os t com p elli ng featu re of th i s dynam i c p olym orp h i s m i s th e abi li ty to h andle h eterog eneou s collecti ons of obj ects . drawElems() i llu s trates th i s concep t: T h e s i m p le ex p res s i on

elems[i]->draw()

res u lts i n i nv ocati ons of di fferent m em ber fu ncti ons , dep endi ng on th e typ e of th e elem ent bei ng i terated ov er.

Page 286: CPlusPlus Templates The Complete Guide

14.2 Static Polymorphism

T em p lates can als o be u s ed to i m p lem ent p olym orp h i s m . H owev er, th ey don' t rely on th e factori ng of com m on beh av i or i n bas e clas s es . I ns tead, th e com m onali ty i s i m p li ci t i n th at th e di fferent " s h ap es " of an ap p li cati on m u s t s u p p ort op erati ons u s i ng com m on s yntax (th at i s , th e relev ant fu ncti ons m u s t h av e th e s am e nam es ). C oncrete clas s es are defi ned i ndep endently from each oth er (s ee F i g u re 14 .2). T h e p olym orp h i c p ower i s th en enabled wh en tem p lates are i ns tanti ated wi th th e concrete clas s es .

Figure 14.2 . Polymorphism implemented via templates

F or ex am p le, th e fu ncti on myDraw() i n th e p rev i ou s s ecti on

void myDraw (GeoObj const& obj) // GeoObj is abstract base class { obj.draw(); }

cou ld concei v ably be rewri tten as follows :

template <typename GeoObj> void myDraw (GeoObj const& obj) // GeoObj is template parameter { obj.draw(); }

C om p ari ng th e two i m p lem entati ons of myDraw(), we m ay conclu de th at th e m ai n di fference i s th e s p eci fi cati on of GeoObj as a tem p late p aram eter i ns tead of a com m on bas e clas s . T h ere are, h owev er, m ore fu ndam ental di fferences u nder th e h ood. F or ex am p le, u s i ng dynam i c p olym orp h i s m we h ad only one myDraw() fu ncti on at ru n ti m e, wh ereas wi th th e tem p late we h av e di s ti nct fu ncti ons , s u ch as myDraw<Line>() and myDraw<Circle>().

W e m ay attem p t to recode th e com p lete ex am p le of th e p rev i ou s s ecti on u s i ng s tati c p olym orp h i s m . F i rs t, i ns tead of a h i erarch y of g eom etri c clas s es , we h av e

Page 287: CPlusPlus Templates The Complete Guide

s ev eral i ndi v i du al g eom etri c clas s es :

// poly/statichier.hpp #include "coord.hpp" // concrete geometric object class Circle // - not derived from any class class Circle { public: void draw() const; Coord center_of_gravity() const; … }; // concrete geometric object class Line // - not derived from any class class Line { public: void draw() const; Coord center_of_gravity() const; … }; …

N ow, th e ap p li cati on of th es e clas s es look s as follows :

// poly/staticpoly.cpp #include "statichier.hpp" #include <vector> // draw any GeoObj template <typename GeoObj> void myDraw (GeoObj const& obj) { obj.draw(); // call draw() according to type of object } // process distance of center of gravity between two GeoObjs template <typename GeoObj1, typename GeoObj2> Coord distance (GeoObj1 const& x1, GeoObj2 const& x2) { Coord c = x1.center_of_gravity() - x2.center_of_gravity(); return c.abs(); // return coordinates as absolute values } // draw homogeneous collection of GeoObjs template <typename GeoObj> void drawElems (std::vector<GeoObj> const& elems) { for (unsigned i=0; i<elems.size(); ++i) { elems[i].draw(); // call draw() according to type of element } }

Page 288: CPlusPlus Templates The Complete Guide

int main() { Line l; Circle c, c1, c2; myDraw(l); // myDraw<Line>(GeoObj&) => Line::draw() myDraw(c); // myDraw<Circle>(GeoObj&) => Circle::draw() distance(c1,c2); // distance<Circle,Circle>(GeoObj1&,GeoObj2&) distance(l,c); // distance<Line,Circle>(GeoObj1&,GeoObj2&) // std::vector<GeoObj*> coll; // ERROR: no inhomogeneous // collection possible std::vector<Line> coll; // OK: homogeneous collection possible coll.push_back(l); // insert line drawElems(coll); // draw all lines }

A s wi th myDraw() , GeoObj can no long er be u s ed as a concrete p aram eter typ e for distance(). I ns tead, we p rov i de for two tem p late p aram eters GeoObj1 and GeoObj2. B y u s i ng two di fferent tem p late p aram eters , di fferent com bi nati ons of g eom etri c obj ect typ es can be accep ted for th e di s tance com p u tati on:

distance(l,c); // distance<Line,Circle>(GeoObj1&,GeoObj2&)

H owev er, h eterog eneou s collecti ons can no long er be h andled trans p arently. T h i s i s wh ere th e stati c p art of stati c poly mor phi sm i m p os es i ts cons trai nt: A ll typ es m u s t be determ i ned at com p i le ti m e. I ns tead, we can eas i ly i ntrodu ce di fferent collecti ons for di fferent g eom etri c obj ect typ es . T h ere i s no long er a req u i rem ent th at th e collecti on be li m i ted to p oi nters , wh i ch can h av e s i g ni fi cant adv antag es i n term s of p erform ance and typ e s afety.

Page 289: CPlusPlus Templates The Complete Guide

14.3 Dynamic versus Static Polymorphism

L et' s categ ori z e and com p are both form s of p olym orp h i s m s .

Terminology

D ynam i c and s tati c p olym orp h i s m p rov i de s u p p ort for di fferent C + + p rog ram m i ng i di om s [3 ]:

[3 ] F or a detai led di s cu s s i on of p olym orp h i s m term i nolog y, s ee als o Secti ons 6.5 to 6.7 of [C z arneck i E i s eneck erG enP rog ] .

• P olym orp h i s m i m p lem ented v i a i nh eri tance i s b ou n d ed and d y n ami c :

- B ou n d ed m eans th at th e i nterfaces of th e typ es p arti ci p ati ng i n th e p olym orp h i c beh av i or are p redeterm i ned by th e des i g n of th e com m on bas e clas s (oth er term s for th i s concep t are i n v asi v e or i n tr u si v e).

- D y n ami c m eans th at th e bi ndi ng of th e i nterfaces i s done at ru n ti m e (dynam i cally).

• P olym orp h i s m i m p lem ented v i a tem p lates i s u n b ou n d ed and stati c :

- U n b ou n d ed m eans th at th e i nterfaces of th e typ es p arti ci p ati ng i n th e p olym orp h i c beh av i or are not p redeterm i ned (oth er term s for th i s concep t are n on i n v asi v e or n on i n tr u si v e).

- S tati c m eans th at th e bi ndi ng of th e i nterfaces i s done at com p i le ti m e (s tati cally).

So, s tri ctly s p eak i ng , i n C + + p arlance, d y n ami c poly mor phi sm and stati c poly mor phi sm are s h ortcu ts for b ou n d ed d y n ami c poly mor phi sm and u n b ou n d ed stati c poly mor phi sm. I n oth er lang u ag es oth er com bi nati ons ex i s t (for ex am p le, Sm alltalk p rov i des u nbou nded dynam i c p olym orp h i s m ). H owev er, i n th e contex t of C + + , th e m ore conci s e term s d y n ami c poly mor phi sm and stati c poly mor phi sm do not cau s e confu s i on.

Strengths and Weaknesses

D ynam i c p olym orp h i s m i n C + + ex h i bi ts th e followi ng s treng th s :

• H eterog eneou s collecti ons are h andled eleg antly. • T h e ex ecu table code s i z e i s p otenti ally s m aller (becau s e only one

p olym orp h i c fu ncti on i s needed, wh ereas di s ti nct tem p late i ns tances m u s t

Page 290: CPlusPlus Templates The Complete Guide

be g enerated to h andle di fferent typ es ). • C ode can be enti rely com p i led; h ence no i m p lem entati on s ou rce m u s t be

p u bli s h ed (di s tri bu ti ng tem p late li brari es u s u ally req u i res di s tri bu ti on of th e s ou rce code of th e tem p late i m p lem entati ons ).

I n contras t, th e followi ng can be s ai d abou t s tati c p olym orp h i s m i n C + + :

• C ollecti ons of bu i lt-i n typ es are eas i ly i m p lem ented. M ore g enerally, th e i nterface com m onali ty need not be ex p res s ed th rou g h a com m on bas e clas s .

• G enerated code i s p otenti ally fas ter (becau s e no i ndi recti on th rou g h p oi nters i s needed a pr i or i and nonv i rtu al fu ncti ons can be i nli ned m u ch m ore often).

• C oncrete typ es th at p rov i de only p arti al i nterfaces can s ti ll be u s ed i f only th at p art ends u p bei ng ex erci s ed by th e ap p li cati on.

Stati c p olym orp h i s m i s often reg arded as m ore ty pe saf e th an dynam i c p olym orp h i s m becau s e all th e bi ndi ng s are ch eck ed at com p i le ti m e. F or ex am p le, th ere i s li ttle dang er of i ns erti ng an obj ect of th e wrong typ e i n a contai ner i ns tanti ated from a tem p late. H owev er, i n a contai ner ex p ecti ng p oi nters to a com m on bas e clas s , th ere i s a p os s i bi li ty th at th es e p oi nters u ni ntenti onally end u p p oi nti ng to com p lete obj ects of di fferent typ es .

I n p racti ce, tem p late i ns tanti ati ons can als o cau s e s om e g ri ef wh en di fferent s em anti c as s u m p ti ons h i de beh i nd i denti cal-look i ng i nterfaces . F or ex am p le, s u rp ri s es can occu r wh en a tem p late th at as s u m es an as s oci ati v e op erator + i s i ns tanti ated for a typ e th at i s not as s oci ati v e wi th res p ect to th at op erator. I n p racti ce, th i s k i nd of s em anti c m i s m atch occu rs les s often wi th i nh eri tance-bas ed h i erarch i es , p res u m ably becau s e th e i nterface s p eci fi cati on i s m ore ex p li ci tly s p eci fi ed.

Combining Both Forms

O f cou rs e, you cou ld com bi ne both form s of i nh eri tance. F or ex am p le, you cou ld deri v e di fferent k i nds of g eom etri c obj ects from a com m on bas e clas s to be able to h andle i nh om og eneou s collecti ons of g eom etri c obj ects . H owev er, you can s ti ll u s e tem p lates to wri te code for a certai n k i nd of g eom etri c obj ect.

T h e com bi nati on of i nh eri tance and tem p lates i s fu rth er des cri bed i n C h ap ter 16. W e wi ll s ee (am ong oth er th i ng s ) h ow th e v i rtu ali ty of a m em ber fu ncti on can be p aram eteri z ed and h ow an addi ti onal am ou nt of flex i bi li ty i s afforded to s tati c p olym orp h i s m u s i ng th e i nh eri tance-bas ed c u r i ou sly r ec u r r i n g template patter n (or CR TP).

Page 291: CPlusPlus Templates The Complete Guide
Page 292: CPlusPlus Templates The Complete Guide

14.4 New Forms of Design Patterns

T h e new form of s tati c p olym orp h i s m leads to new ways of i m p lem enti ng des i g n p atterns . T ak e, for ex am p le, th e b r i d g e patter n , wh i ch p lays a m aj or role i n C + + p rog ram s . O ne g oal of u s i ng th e bri dg e p attern i s to s wi tch between di fferent i m p lem entati ons of an i nterface. A ccordi ng to [D es i g nP atterns G oV ] th i s i s u s u ally done by u s i ng a p oi nter to refer to th e actu al i m p lem entati on and deleg ati ng all calls to th i s clas s (s ee F i g u re 14 .3 ).

Figure 14.3 . B ridge pattern implemented using inheritance

H owev er, i f th e typ e of th e i m p lem entati on i s k nown at com p i le ti m e, you cou ld u s e th e ap p roach v i a tem p lates i ns tead (s ee F i g u re 14 .4 ). T h i s leads to m ore typ e s afety, av oi ds p oi nters , and s h ou ld be fas ter.

Figure 14.4. B ridge pattern implemented using templates

Page 293: CPlusPlus Templates The Complete Guide

14.5 Generic Programming

Stati c p olym orp h i s m leads to th e concep t of g en er i c pr og r ammi n g . H owev er, th ere i s no one u ni v ers ally ag reed-on defi ni ti on of g en er i c pr og r ammi n g (j u s t as th ere i s no one ag reed-on defi ni ti on of ob j ec t-or i en ted pr og r ammi n g ). A ccordi ng to [Cz ar n ec k i E i sen ec k er Gen Pr og ] , defi ni ti ons g o from pr og r ammi n g w i th g en er i c par ameter s to f i n d i n g the most ab str ac t r epr esen tati on of ef f i c i en t alg or i thms. T h e book s u m m ari z es :

Gen er i c pr og r ammi n g i s a su b d i sc i pli n e of c ompu ter sc i en c e that d eals w i th f i n d i n g ab str ac t r epr esen tati on s of ef f i c i en t alg or i thms, d ata str u c tu r es, an d other sof tw ar e c on c epts, an d w i th thei r sy stemati c or g an i z ati on …. Gen er i c pr og r ammi n g f oc u ses on r epr esen ti n g f ami li es of d omai n c on c epts. (p ag es 169 and 17 0)

I n th e contex t of C + + , g eneri c p rog ram m i ng i s s om eti m es defi ned as pr og r ammi n g w i th templates (wh ereas obj ect-ori ented p rog ram m i ng i s th ou g h t of as pr og r ammi n g w i th v i r tu al f u n c ti on s). I n th i s s ens e, j u s t abou t any u s e of C + + tem p lates cou ld be th ou g h t of as an i ns tance of g eneri c p rog ram m i ng . H owev er, p racti ti oners often th i nk of g eneri c p rog ram m i ng as h av i ng an addi ti onal es s enti al i ng redi ent: T em p lates h av e to be des i g ned i n a fram ework for th e p u rp os e of enabli ng a m u lti tu de of u s efu l com bi nati ons .

B y far th e m os t s i g ni fi cant contri bu ti on i n th i s area i s th e ST L (th e S tan d ar d Template L i b r ar y , wh i ch later was adap ted and i ncorp orated i nto th e C + + s tandard li brary). T h e ST L i s a fram ework th at p rov i des a nu m ber of u s efu l op erati ons , called alg or i thms , for a nu m ber of li near data s tru ctu res for collecti ons of obj ects , called c on tai n er s. B oth alg ori th m s and contai ners are tem p lates . H owev er, th e k ey i s th at th e alg ori th m s are n ot m em ber fu ncti ons of th e contai ners . I ns tead, th e alg ori th m s are wri tten i n a g en er i c way s o th at th ey can be u s ed by any contai ner (and li near collecti on of elem ents ). T o do th i s , th e des i g ners of ST L i denti fi ed an abs tract concep t of i ter ator s th at can be p rov i ded for any k i nd of li near collecti on. E s s enti ally, th e collecti on-s p eci fi c as p ects of contai ner op erati ons h av e been factored ou t i nto th e i terators ' fu ncti onali ty.

A s a cons eq u ence, i m p lem enti ng an op erati on s u ch as com p u ti ng th e m ax i m u m v alu e i n a s eq u ence can be done wi th ou t k nowi ng th e detai ls of h ow v alu es are s tored i n th at s eq u ence:

template <class Iterator> Iterator max_element (Iterator beg, // refers to start of collection

Page 294: CPlusPlus Templates The Complete Guide

Iterator end) // refers to end of collection { // use only certain Iterator's operations to traverse all elements // of the collection to find the element with the maximum value // and return its position as Iterator … }

I ns tead of p rov i di ng all u s efu l op erati ons s u ch as max_element() by ev ery li near contai ner, th e contai ner h as to p rov i de only an i terator typ e to trav ers e th e s eq u ence of v alu es i t contai ns and m em ber fu ncti ons to create s u ch i terators :

namespace std { template <class T, … > class vector { public: typedef … const_iterator; // implementation-specific iterator … // type for constant vectors const_iterator begin() const; // iterator for start of collection const_iterator end() const; // iterator for end of collection … }; template <class T, ... > class list { public: typedef … const_iterator; // implementation-specific iterator … // type for constant lists const_iterator begin() const; // iterator for start of collection const_iterator end() const; // iterator for end of collection … }; }

N ow, you can fi nd th e m ax i m u m of any collecti on by calli ng th e g en er i c max_element() op erati on wi th th e beg i nni ng and end of th e collecti on as arg u m ents (s p eci al h andli ng of em p ty collecti ons i s om i tted):

// poly/printmax.cpp #include <vector> #include <list> #include <algorithm> #include <iostream> #include "MyClass.hpp" template <typename T> void print_max (T const& coll)

Page 295: CPlusPlus Templates The Complete Guide

{ // declare local iterator of collection typename T::const_iterator pos; // compute position of maximum value pos = std::max_element(coll.begin(),coll.end()); // print value of maximum element of coll (if any): if (pos != coll.end()) { std::cout << *pos << std::endl; } else { std::cout << "empty" << std::endl; } } int main() { std::vector<MyClass> c1; std::list<MyClass> c2; … print_max (c1); print_max (c2); }

B y p aram eteri z i ng i ts op erati ons i n term s of th es e i terators , th e ST L av oi ds an ex p los i on i n th e nu m ber of op erati on defi ni ti ons . I ns tead of i m p lem enti ng each op erati on for ev ery contai ner, you i m p lem ent th e alg ori th m once s o th at i t can be u s ed for ev ery contai ner. T h e g en er i c g lu e i s th e i terators th at are p rov i ded by th e contai ners and th at are u s ed by th e alg ori th m s . T h i s work s becau s e i terators h av e a certai n i nterface th at i s p rov i ded by th e contai ners and u s ed by th e alg ori th m s . T h i s i nterface i s u s u ally called a c on c ept , wh i ch denotes a s et of cons trai nts th at a tem p late h as to fu lfi ll to fi t i nto th i s fram ework .

I n p ri nci p le, fu ncti onally s u ch as an ST L -li k e ap p roach cou ld be i m p lem ented wi th dynam i c p olym orp h i s m . I n p racti ce, h owev er, i t wou ld be of li m i ted u s e becau s e th e i terator concep t i s too li g h twei g h t com p ared wi th th e v i rtu al fu ncti on call m ech ani s m . A ddi ng an i nterface layer bas ed on v i rtu al fu ncti ons wou ld m os t li k ely s low down ou r op erati ons by an order of m ag ni tu de (or m ore).

G eneri c p rog ram m i ng i s p racti cal ex actly becau s e i t reli es on s tati c p olym orp h i s m , wh i ch res olv es i nterfaces at com p i le ti m e. O n th e oth er h and, th e req u i rem ent th at th e i nterfaces be res olv ed at com p i le ti m e als o calls for new des i g n p ri nci p les th at are di fferent i n m any ways from obj ect-ori ented des i g n p ri nci p les . M any of th e m os t i m p ortant of th es e g en er i c d esi g n pr i n c i ples are des cri bed i n th e rem ai nder of th i s book .

Page 296: CPlusPlus Templates The Complete Guide

14.6 Afternotes

C ontai ner typ es were a p ri m ary m oti v ati on for th e i ntrodu cti on of tem p lates i nto th e C + + p rog ram m i ng lang u ag e. P ri or to tem p lates , p olym orp h i c h i erarch i es were a p op u lar ap p roach to contai ners . A p op u lar ex am p le was th e N ati onal I ns ti tu tes of H ealth C las s L i brary (N I H C L ), wh i ch to a larg e ex tent trans lated th e contai ner clas s h i erarch y of Sm alltalk (s ee F i g u re 14 .5 ).

Figure 14.5 . C lass hierarchy of the N I H C L

M u ch li k e th e C + + s tandard li brary, th e N I H C L s u p p orted a ri ch v ari ety of contai ners as well as i terators . H owev er, th e i m p lem entati on followed th e Sm alltalk s tyle of dynam i c p olym orp h i s m : Iterator s u s ed th e abs tract bas e clas s Collection to op erate on di fferent typ es of collecti ons :

Bag c1; Set c2; … Iterator i1(s); Iterator i2(b); …

U nfortu nately, th e p ri ce of th i s ap p roach was h i g h both i n term s of ru nni ng ti m e and m em ory u s ag e. R u nni ng ti m e was typ i cally orders of m ag ni tu de wors e th an eq u i v alent code u s i ng th e C + + s tandard li brary becau s e m os t op erati ons ended u p req u i ri ng a v i rtu al call (wh ereas i n th e C + + s tandard li brary m any op erati ons are i nli ned, and no v i rtu al fu ncti ons are i nv olv ed i n i terator and contai ner i nterfaces ). F u rth erm ore, becau s e (u nli k e Sm alltalk ) th e i nterfaces were

Page 297: CPlusPlus Templates The Complete Guide

bou nded, bu i lt-i n typ es h ad to be wrap p ed i n larg er p olym orp h i c clas s es (s u ch wrap p ers were p rov i ded by th e N I H C L ), wh i ch i n tu rn cou ld lead to dram ati c i ncreas es i n s torag e req u i rem ents .

Som e s ou g h t s olace i n m acros , bu t ev en i n today' s ag e of tem p lates m any p roj ects s ti ll m ak e s u bop ti m al ch oi ces i n th ei r ap p roach to p olym orp h i s m . C learly th ere are m any s i tu ati ons wh en dynam i c p olym orp h i s m i s th e " ri g h t ch oi ce." H eterog eneou s i terati ons are an ex am p le. H owev er, i n th e s am e v ei n, m any p rog ram m i ng tas k s are natu rally and effi ci ently s olv ed u s i ng tem p lates , and h om og eneou s contai ners are an ex am p le of th i s .

Stati c p olym orp h i s m lends i ts elf well to code v ery fu ndam ental com p u ti ng s tru ctu res . I n contras t, th e need to ch oos e a com m on bas e typ e i m p li es th at a dynam i c p olym orp h i c li brary wi ll norm ally h av e to m ak e dom ai n-s p eci fi c ch oi ces . I t' s no s u rp ri s e th en th at th e ST L p art of th e C + + s tandard li brary nev er i nclu ded p olym orp h i c contai ners , bu t i t contai ns a ri ch s et of contai ners and i terators th at u s e s tati c p olym orp h i s m (as dem ons trated i n Secti on 14 .5 on p ag e 24 1).

M edi u m and larg e C + + p rog ram s typ i cally need to h andle both k i nds of p olym orp h i s m di s cu s s ed i n th i s ch ap ter. I n s om e s i tu ati ons i t m ay ev en be neces s ary to com bi ne th em v ery i nti m ately. I n m any cas es th e op ti m al des i g n ch oi ces are clear i n li g h t of ou r di s cu s s i on, bu t s p endi ng s om e ti m e th i nk i ng abou t long -term p otenti al ev olu ti ons alm os t always p ays off.

Page 298: CPlusPlus Templates The Complete Guide

Chapter 15. Traits and Policy Classes

T em p lates enable u s to p aram eteri z e clas s es and fu ncti ons for v ari ou s typ es . I t cou ld be tem p ti ng to i ntrodu ce as m any tem p late p aram eters as p os s i ble to enable th e cu s tom i z ati on of ev ery as p ect of a typ e or alg ori th m . I n th i s way, ou r " tem p lati z ed" com p onents cou ld be i ns tanti ated to m eet th e ex act needs of cli ent code. H owev er, from a p racti cal p oi nt of v i ew i t i s rarely des i rable to i ntrodu ce doz ens of tem p late p aram eters for m ax i m al p aram eteri z ati on. H av i ng to s p eci fy all th e corres p ondi ng arg u m ents i n th e cli ent code i s ov erly tedi ou s .

F ortu nately, i t tu rns ou t th at m os t of th e ex tra p aram eters we wou ld i ntrodu ce h av e reas onable defau lt v alu es . I n s om e cas es th e ex tra p aram eters are enti rely determ i ned by a few mai n p aram eters , and we' ll s ee th at s u ch ex tra p aram eters can be om i tted altog eth er. O th er p aram eters can be g i v en defau lt v alu es th at dep end on th e m ai n p aram eters and wi ll m eet th e needs of m os t s i tu ati ons , bu t th e defau lt v alu es m u s t occas i onally be ov erri dden (for s p eci al ap p li cati ons ). Y et oth er p aram eters are u nrelated to th e m ai n p aram eters : I n a s ens e th ey are th em s elv es m ai n p aram eters , ex cep t for th e fact th at th ere ex i s t defau lt v alu es th at alm os t always fi t th e bi ll.

Poli c y c lasses and tr ai ts (or tr ai ts templates) are C + + p rog ram m i ng dev i ces th at g reatly faci li tate th e m anag em ent of th e s ort of ex tra p aram eters th at com e u p i n th e des i g n of i ndu s tri al-s treng th tem p lates . I n th i s ch ap ter we s h ow a nu m ber of s i tu ati ons i n wh i ch th ey p rov e u s efu l and dem ons trate v ari ou s tech ni q u es th at wi ll enable you to wri te robu s t and p owerfu l dev i ces of you r own.

Page 299: CPlusPlus Templates The Complete Guide

15.1 An Example: Accumulating a Sequence

C om p u ti ng th e s u m of a s eq u ence of v alu es i s a fai rly com m on com p u tati onal tas k . H owev er, th i s s eem i ng ly s i m p le p roblem p rov i des u s wi th an ex cellent ex am p le to i ntrodu ce v ari ou s lev els at wh i ch p oli cy clas s es and trai ts can h elp .

15.1.1 Fixed Traits

L et' s fi rs t as s u m e th at th e v alu es of th e s u m we want to com p u te are s tored i n an array, and we are g i v en a p oi nter to th e fi rs t elem ent to be accu m u lated and a p oi nter one p as t th e las t elem ent to be accu m u lated. B ecau s e th i s book i s abou t tem p lates , we wi s h to wri te a tem p late th at wi ll work for m any typ es . T h e followi ng m ay s eem s trai g h tforward by now [1]:

[1] M os t ex am p les i n th i s s ecti on u s e ordi nary p oi nters for th e s ak e of s i m p li ci ty. C learly, an i ndu s tri al-s treng th i nterface m ay p refer to u s e i terator p aram eters followi ng th e conv enti ons of th e C + + s tandard li brary (s ee [J os u tti s StdL i b] ). W e rev i s i t th i s as p ect of ou r ex am p le later.

// traits/accum1.hpp #ifndef ACCUM_HPP #define ACCUM_HPP template <typename T> inline T accum (T const* beg, T const* end) { T total = T(); // assume T() actually creates a zero value while (beg != end) { total += *beg; ++beg; } return total; } #endif // ACCUM_HPP

T h e only s li g h tly s u btle deci s i on h ere i s h ow to create a z er o v alu e of th e correct typ e to s tart ou r s u m m ati on. W e u s e th e ex p res s i on T() h ere, wh i ch norm ally s h ou ld work for bu i lt-i n nu m eri c typ es li k e int and float (s ee Secti on 5 .5 on p ag e 5 6).

T o m oti v ate ou r fi rs t trai ts tem p late, cons i der th e followi ng code th at m ak es u s e of ou r accum():

Page 300: CPlusPlus Templates The Complete Guide

// traits/accum1.cpp #include "accum1.hpp" #include <iostream> int main() { // create array of 5 integer values int num[]={1,2,3,4,5}; // print average value std::cout << "the average value of the integer values is " << accum(&num[0], &num[5]) / 5 << '\n'; // create array of character values char name[] = "templates"; int length = sizeof(name)-1; // (try to) print average character value std::cout << "the average value of the characters in \"" << name << "\" is " << accum(&name[0], &name[length]) / length << '\n'; }

I n th e fi rs t h alf of th e p rog ram we u s e accum() to s u m fi v e i nteg er v alu es :

int num[]={1,2,3,4,5}; … accum(&num[0], &num[5])

T h e av erag e i nteg er v alu e i s th en obtai ned by s i m p ly di v i di ng th e res u lti ng s u m by th e nu m ber of v alu es i n th e array.

T h e s econd h alf of th e p rog ram attem p ts to do th e s am e for all letters i n th e word template (p rov i ded th e ch aracters from a to z form a conti g u ou s s eq u ence i n th e actu al ch aracter s et, wh i ch i s tru e for A SC I I bu t not for E B C D I C [2 ]). T h e res u lt s h ou ld p res u m ably li e between th e v alu e of a and th e v alu e of z. O n m os t p latform s today, th es e v alu es are determ i ned by th e A SC I I codes : a i s encoded as 9 7 and z i s encoded as 122. H ence, we m ay ex p ect a res u lt between 9 7 and 122. H owev er, on ou r p latform th e ou tp u t of th e p rog ram i s as follows :

[2 ] E B C D I C i s an abbrev i ati on of E x tended B i nary-C oded D eci m al I nterch ang e C ode, wh i ch i s an I B M ch aracter s et th at i s wi dely u s ed on larg e I B M com p u ters .

the average value of the integer values is 3 the average value of the characters in "templates" is -5

T h e p roblem h ere i s th at ou r tem p late was i ns tanti ated for th e typ e char, wh i ch

Page 301: CPlusPlus Templates The Complete Guide

tu rns ou t to be too by i ntrodu ci ng an addi ti onal tem p late p aram eter AccT th at des cri bes th e typ e u s ed for th e v ari able total (and h ence th e retu rn typ e). H owev er, th i s wou ld p u t an ex tra bu rden on all u s ers of ou r tem p late: T h ey wou ld h av e to s p eci fy an ex tra typ e i n ev ery i nv ocati on of ou r tem p late. I n ou r ex am p le we m ay, th erefore, need to wri te th e followi ng :

accum<int>(&name[0],&name[length])

T h i s i s not an ex ces s i v e cons trai nt, bu t i t can be av oi ded.

A n alternati v e ap p roach to th e ex tra p aram eter i s to create an as s oci ati on between each typ e T for wh i ch accum() i s called and th e corres p ondi ng typ e th at s h ou ld be u s ed to h old th e accu m u lated v alu e. T h i s as s oci ati on cou ld be cons i dered ch aracteri s ti c of th e typ e T , and th erefore th e typ e i n wh i ch th e s u m i s com p u ted i s s om eti m es called a tr ai t of T. A s i s tu rns ou t, ou r as s oci ati on can be encoded as s p eci ali z ati ons of a tem p late:

// traits/accumtraits2.hpp template<typename T> class AccumulationTraits; template<> class AccumulationTraits<char> { public: typedef int AccT; }; template<> class AccumulationTraits<short> { public: typedef int AccT; }; template<> class AccumulationTraits<int> { public: typedef long AccT; }; template<> class AccumulationTraits<unsigned int> { public: typedef unsigned long AccT; }; template<> class AccumulationTraits<float> { public: typedef double AccT; };

Page 302: CPlusPlus Templates The Complete Guide

T h e tem p late AccumulationTraits i s called a tr ai ts template becau s e i t h olds a trai t of i ts p aram eter typ e. (I n g eneral, th ere cou ld be m ore th an one trai t and m ore th an one p aram eter.) W e ch os e not to p rov i de a g eneri c defi ni ti on of th i s tem p late becau s e th ere i s n' t a g reat way to s elect a g ood accu m u lati on typ e wh en we don' t k now wh at th e typ e i s . H owev er, an arg u m ent cou ld be m ade th at T i ts elf i s often a g ood candi date for s u ch a typ e (alth ou g h clearly not i n ou r earli er ex am p le).

W i th th i s i n m i nd, we can rewri te ou r accum() tem p late as follows :

// traits/accum2.hpp #ifndef ACCUM_HPP #define ACCUM_HPP #include "accumtraits2.hpp" template <typename T> inline typename AccumulationTraits<T>::AccT accum (T const* beg, T const* end) { // return type is traits of the element type typedef typename AccumulationTraits<T>::AccT AccT; AccT total = AccT(); // assume T() actually creates a zero value while (beg != end) { total += *beg; ++beg; } return total; } #endif // ACCUM_HPP

T h e ou tp u t of ou r s am p le p rog ram th en becom es wh at we ex p ect:

the average value of the integer values is 3 the average value of the characters in "templates" is 108

O v erall, th e ch ang es aren' t v ery dram ati c cons i deri ng th at we h av e added a v ery u s efu l m ech ani s m to cu s tom i z e ou r alg ori th m . F u rth erm ore, i f new typ es ari s e for u s e wi th accum(), an ap p rop ri ate AccT can be as s oci ated wi th i t s i m p ly by declari ng an addi ti onal ex p li ci t s p eci ali z ati on of th e AccumulationTraits tem p late. N ote th at th i s can be done for any typ e: fu ndam ental typ es , typ es th at are declared i n oth er li brari es , and s o forth .

15.1.2 Value Traits

Page 303: CPlusPlus Templates The Complete Guide

So far, we h av e s een th at trai ts rep res ent addi ti onal typ e i nform ati on related to a g i v en " m ai n" typ e. I n th i s s ecti on we s h ow th at th i s ex tra i nform ati on need not be li m i ted to typ es . C ons tants and oth er clas s es of v alu es can be as s oci ated wi th a typ e as well.

O u r ori g i nal accum() tem p late u s es th e defau lt cons tru ctor of th e retu rn v alu e to i ni ti ali z e th e res u lt v ari able wi th wh at i s h op ed to be a z ero-li k e v alu e:

AccT total = AccT(); // assume T() actually creates a zero value … return total;

C learly, th ere i s no g u arantee th at th i s p rodu ces a g ood v alu e to s tart th e accu m u lati on loop . T yp e T m ay not ev en h av e a defau lt cons tru ctor.

A g ai n, trai ts can com e to th e res cu e. F or ou r ex am p le, we can add a new v alu e tr ai t to ou r AccumulationTraits:

// traits/accumtraits3.hpp template<typename T> class AccumulationTraits; template<> class AccumulationTraits<char> { public: typedef int AccT; static AccT const zero = 0; }; template<> class AccumulationTraits<short> { public: typedef int AccT; static AccT const zero = 0; }; template<> class AccumulationTraits<int> { public: typedef long AccT; static AccT const zero = 0; }; …

I n th i s cas e, ou r new trai t i s a cons tant th at can be ev alu ated at com p i le ti m e. T h u s , accum() becom es :

// traits/accum3.hpp #ifndef ACCUM_HPP

Page 304: CPlusPlus Templates The Complete Guide

#define ACCUM_HPP #include "accumtraits3.hpp" template <typename T> inline typename AccumulationTraits<T>::AccT accum (T const* beg, T const* end) { // return type is traits of the element type typedef typename AccumulationTraits<T>::AccT AccT; AccT total = AccumulationTraits<T>::zero; while (beg != end) { total += *beg; ++beg; } return total; } #endif // ACCUM_HPP

I n th i s code, th e i ni ti ali z ati on of th e accu m u lati on v ari able rem ai ns s trai g h tforward:

AccT total = AccumulationTraits<T>::zero;

A drawback of th i s form u lati on i s th at C + + allows u s to i ni ti ali z e only a s tati c cons tant data m em ber i ns i de i ts clas s i f i t h as an i nteg ral or enu m erati on typ e. T h i s ex clu des ou r own clas s es , of cou rs e, and floati ng -p oi nt typ es as well. T h e followi ng s p eci ali z ati on i s , th erefore, an error:

… template<> class AccumulationTraits<float> { public: typedef double AccT; static double const zero = 0.0; // ERROR: not an integral type };

T h e s trai g h tforward alternati v e i s not to defi ne th e v alu e trai t i n i ts clas s :

… template<> class AccumulationTraits<float> { public: typedef double AccT; static double const zero; };

T h e i ni ti ali z er th en g oes i n a s ou rce fi le and look s s om eth i ng li k e th e followi ng :

Page 305: CPlusPlus Templates The Complete Guide

… double const AccumulationTraits<float>::zero = 0.0;

A lth ou g h th i s work s , i t h as th e di s adv antag e of bei ng m ore op aq u e to com p i lers . W h i le p roces s i ng cli ent fi les , com p i lers are typ i cally u naware of defi ni ti ons i n oth er fi les . I n th i s cas e, for ex am p le, a com p i ler wou ld not be able to tak e adv antag e of th e fact th at th e v alu e zero i s really 0.0.

C ons eq u ently, we p refer to i m p lem ent v alu e trai ts , wh i ch are not g u aranteed to h av e i nteg ral v alu es as i nli ne m em ber fu ncti ons . [3 ] F or ex am p le, we cou ld rewri te AccumulationTraits as follows :

[3 ] M os t m odern C + + com p i lers can " s ee th rou g h " calls of s i m p le i nli ne fu ncti ons .

// traits/accumtraits4.hpp template<typename T> class AccumulationTraits; template<> class AccumulationTraits<char> { public: typedef int AccT; static AccT zero() { return 0; } }; template<> class AccumulationTraits<short> { public: typedef int AccT; static AccT zero() { return 0; } }; template<> class AccumulationTraits<int> { public: typedef long AccT; static AccT zero() { return 0; } }; template<> class AccumulationTraits<unsigned int> { public: typedef unsigned long AccT; static AccT zero() { return 0; } };

Page 306: CPlusPlus Templates The Complete Guide

template<> class AccumulationTraits<float> { public: typedef double AccT; static AccT zero() { return 0; } }; …

F or th e ap p li cati on code, th e only di fference i s th e u s e of fu ncti on call s yntax (i ns tead of th e s li g h tly m ore conci s e acces s to a s tati c data m em ber):

AccT total = AccumulationTraits<T>::zero();

C learly, trai ts can be m ore th an j u s t ex tra ty pes. I n ou r ex am p le, th ey can be a m ech ani s m to p rov i de all th e neces s ary i nform ati on th at accum() needs abou t th e elem ent typ e for wh i ch i t i s called. T h i s i s th e k ey of th e trai ts concep t: T rai ts p rov i de an av enu e to c on f i g u r e concrete elem ents (m os tly typ es ) for g eneri c com p u tati ons .

15.1.3 Parameterized Traits

T h e u s e of trai ts i n accum() i n th e p rev i ou s s ecti ons i s called f i x ed , becau s e once th e decou p led trai t i s defi ned, i t cannot be ov erri dden i n th e alg ori th m . T h ere m ay be cas es wh en s u ch ov erri di ng i s des i rable. F or ex am p le, we m ay h ap p en to k now th at a s et of float v alu es can s afely be s u m m ed i nto a v ari able of th e s am e typ e, and doi ng s o m ay bu y u s s om e effi ci ency.

I n p ri nci p le, th e s olu ti on cons i s ts of addi ng a tem p late p aram eter bu t wi th a defau lt v alu e determ i ned by ou r trai ts tem p late. I n th i s way, m any u s ers can om i t th e ex tra tem p late arg u m ent, bu t th os e wi th m ore ex cep ti onal needs can ov erri de th e p res et accu m u lati on typ e. T h e only bee i n ou r bonnet for th i s p arti cu lar cas e i s th at fu ncti on tem p lates cannot h av e defau lt tem p late arg u m ents . [4 ]

[4 ] T h i s i s alm os t certai nly g oi ng to ch ang e i n a rev i s i on of th e C + + s tandard, and com p i ler v endors are li k ely to p rov i de th e featu re ev en before th i s rev i s ed s tandard i s p u bli s h ed (s ee Secti on 13 .3 on p ag e 207 ).

F or now, let' s ci rcu m v ent th e p roblem by form u lati ng ou r alg ori th m as a clas s . T h i s als o i llu s trates th e fact th at trai ts can be u s ed i n clas s tem p lates at leas t as eas i ly as i n fu ncti on tem p lates . T h e drawback i n ou r ap p li cati on i s th at clas s tem p lates cannot h av e th ei r tem p late arg u m ents dedu ced. T h ey m u s t be p rov i ded ex p li ci tly. H ence, we need th e form

Accum<char>::accum(&name[0], &name[length])

Page 307: CPlusPlus Templates The Complete Guide

to u s e ou r rev i s ed accu m u lati on tem p late:

// traits/accum5.hpp #ifndef ACCUM_HPP #define ACCUM_HPP #include "accumtraits4.hpp" template <typename T, typename AT = AccumulationTraits<T> > class Accum { public: static typename AT::AccT accum (T const* beg, T const* end) { typename AT::AccT total = AT::zero(); while (beg != end) { total += *beg; ++beg; } return total; } }; #endif // ACCUM_HPP

P res u m ably, m os t u s ers of th i s tem p late wou ld nev er h av e to p rov i de th e s econd tem p late arg u m ent ex p li ci tly becau s e i t can be confi g u red to an ap p rop ri ate defau lt for ev ery typ e u s ed as a fi rs t arg u m ent.

A s i s often th e cas e, we can i ntrodu ce conv eni ence fu ncti ons to s i m p li fy th e i nterface:

template <typename T> inline typename AccumulationTraits<T>::AccT accum (T const* beg, T const* end) { return Accum<T>::accum(beg, end); } template <typename Traits, typename T> inline typename Traits::AccT accum (T const* beg, T const* end) { return Accum<T, Traits>::accum(beg, end); }

15.1.4 Policies and Policy Classes

So far we h av e eq u ated ac c u mu lati on wi th su mmati on . C learly we can i m ag i ne oth er k i nds of accu m u lati ons . F or ex am p le, we cou ld m u lti p ly th e s eq u ence of g i v en v alu es . O r, i f th e v alu es were s tri ng s , we cou ld concatenate th em . E v en

Page 308: CPlusPlus Templates The Complete Guide

fi ndi ng th e m ax i m u m v alu e i n a s eq u ence cou ld be form u lated as an accu m u lati on p roblem . I n all th es e alternati v es , th e only accum() op erati on th at needs to ch ang e i s total += *start. T h i s op erati on can be called a poli c y of ou r accu m u lati on p roces s . A p oli cy clas s , th en, i s a clas s th at p rov i des an i nterface to ap p ly one or m ore p oli ci es i n an alg ori th m . [5 ]

[5 ] W e cou ld g enerali z e th i s to a poli c y par ameter , wh i ch cou ld be a clas s (as di s cu s s ed) or a p oi nter to a fu ncti on.

H ere i s an ex am p le of h ow we cou ld i ntrodu ce s u ch an i nterface i n ou r Accum clas s tem p late:

// traits/accum6.hpp #ifndef ACCUM_HPP #define ACCUM_HPP #include "accumtraits4.hpp" #include "sumpolicy1.hpp" template <typename T, typename Policy = SumPolicy, typename Traits = AccumulationTraits<T> > class Accum { public: typedef typename Traits::AccT AccT; static AccT accum (T const* beg, T const* end) { AccT total = Traits::zero(); while (beg != end) { Policy::accumulate(total, *beg); ++beg; } return total; } }; #endif // ACCUM_HPP

W i th th i s a SumPolicy cou ld be wri tten as follows :

// traits/sumpolicy1.hpp #ifndef SUMPOLICY_HPP #define SUMPOLICY_HPP class SumPolicy { public: template<typename T1, typename T2> static void accumulate (T1& total, T2 const & value) { total += value; } }; #endif // SUMPOLICY_HPP

Page 309: CPlusPlus Templates The Complete Guide

I n th i s ex am p le we ch os e to m ak e ou r p oli cy an ordi nary clas s (th at i s , not a tem p late) wi th a s tati c m em ber fu ncti on tem p late (wh i ch i s i m p li ci tly i nli ne). W e di s cu s s an alternati v e op ti on later.

B y s p eci fyi ng a di fferent p oli cy to accu m u late v alu es we can com p u te di fferent th i ng s . C ons i der, for ex am p le, th e followi ng p rog ram , wh i ch i ntends to determ i ne th e p rodu ct of s om e v alu es :

// traits/accum7.cpp #include "accum6.hpp" #include <iostream> class MultPolicy { public: template<typename T1, typename T2> static void accumulate (T1& total, T2 const& value) { total *= value; } }; int main() { // create array of 5 integer values int num[]={1,2,3,4,5}; // print product of all values std::cout << "the product of the integer values is " << Accum<int,MultPolicy>::accum(&num[0], &num[5]) << '\n'; }

H owev er, th e ou tp u t of th i s p rog ram i s n' t wh at we wou ld li k e:

the product of the integer values is 0

T h e p roblem h ere i s cau s ed by ou r ch oi ce of i ni ti al v alu e: A lth ou g h 0 work s well for s u m m ati on, i t does not work for m u lti p li cati on (a z ero i ni ti al v alu e forces a z ero res u lt for accu m u lated m u lti p li cati ons ). T h i s i llu s trates th at di fferent trai ts and p oli ci es m ay i nteract, u nders cori ng th e i m p ortance of carefu l tem p late des i g n.

I n th i s cas e we m ay recog ni z e th at th e i ni ti ali z ati on of an accu m u lati on loop i s a p art of th e accu m u lati on p oli cy. T h i s p oli cy m ay or m ay not m ak e u s e of th e trai t zero(). O th er alternati v es are not to be forg otten: N ot ev eryth i ng m u s t be s olv ed wi th trai ts and p oli ci es . F or ex am p le, th e accumulate() fu ncti on of th e C + + s tandard li brary tak es th e i ni ti al v alu e as a th i rd (fu ncti on call) arg u m ent.

Page 310: CPlusPlus Templates The Complete Guide

15.1.5 Traits and Policies: What's the Difference?

A reas onable cas e can be m ade i n s u p p ort of th e fact th at p oli ci es are j u s t a s p eci al cas e of trai ts . C onv ers ely, i t cou ld be clai m ed th at trai ts j u s t encode a p oli cy.

T h e New S hor ter O x f or d E n g li sh D i c ti on ar y (s ee [N ewSh orterO E D ] ) h as th i s to s ay:

• trait n . . . . a d i sti n c ti v e f eatu r e c har ac ter i z i n g a thi n g • policy n . . . . an y c ou r se of ac ti on ad opted as ad v an teg ou s or ex ped i en t

B as ed on th i s , we tend to li m i t th e u s e of th e term poli c y c lasses to clas s es th at encode an acti on of s om e s ort th at i s larg ely orth og onal wi th res p ect to any oth er tem p late arg u m ent wi th wh i ch i t i s com bi ned. T h i s i s i n ag reem ent wi th A ndrei A lex andres cu ' s s tatem ent i n h i s book M od er n C++ D esi g n (s ee p ag e 8 of [A lex andres cu D es i g n] ) [6 ]:

[6 ] A lex andres cu h as been th e m ai n v oi ce i n th e world of p oli cy clas s es , and h e h as dev elop ed a ri ch s et of tech ni q u es bas ed on th em .

Poli c i es hav e mu c h i n c ommon w i th tr ai ts b u t d i f f er i n that they pu t less emphasi s on ty pe an d mor e on b ehav i or .

N ath an M yers , wh o i ntrodu ced th e trai ts tech ni q u e, p rop os ed th e followi ng m ore op en-ended defi ni ti on (s ee [M yers T rai ts ] ):

Tr ai ts c lass: A c lass u sed i n plac e of template par ameter s. As a c lass, i t ag g r eg ates u sef u l ty pes an d c on stan ts; as a template, i t pr ov i d es an av en u e f or that " ex tr a lev el of i n d i r ec ti on " that solv es all sof tw ar e pr ob lems.

I n g eneral, we th erefore tend to u s e th e followi ng (s li g h tly fu z z y) defi ni ti ons :

• T raits rep res ent natu ral addi ti onal p rop erti es of a tem p late p aram eter. • Policies rep res ent confi g u rable beh av i or for g eneri c fu ncti ons and typ es

(often wi th s om e com m only u s ed defau lts ).

T o elaborate fu rth er on th e p os s i ble di s ti ncti ons between th e two concep ts , we li s t th e followi ng obs erv ati ons abou t trai ts :

• T rai ts can be u s efu l as f i x ed tr ai ts (th at i s , wi th ou t bei ng p as s ed th rou g h tem p late p aram eters ).

• T rai ts p aram eters u s u ally h av e v ery natu ral defau lt v alu es (wh i ch are rarely ov erri dden, or s i m p ly cannot be ov erri dden).

Page 311: CPlusPlus Templates The Complete Guide

• T rai ts p aram eters tend to dep end ti g h tly on one or m ore m ai n p aram eters . • T rai ts m os tly com bi ne typ es and cons tants rath er th an m em ber fu ncti ons . • T rai ts tend to be collected i n trai ts templates.

F or p oli cy clas s es , we m ak e th e followi ng obs erv ati ons :

• P oli cy clas s es don' t contri bu te m u ch i f th ey aren' t p as s ed as tem p late p aram eters .

• P oli cy p aram eters need not h av e defau lt v alu es and are often s p eci fi ed ex p li ci tly (alth ou g h m any g eneri c com p onents are confi g u red wi th com m only u s ed defau lt p oli ci es ).

• P oli cy p aram eters are m os tly orth og onal to oth er p aram eters of a tem p late.

• P oli cy clas s es m os tly com bi ne m em ber fu ncti ons . • P oli ci es can be collected i n p lai n clas s es or i n clas s tem p lates .

H owev er, th ere i s certai nly an i ndi s ti nct li ne between both term s . F or ex am p le, th e ch aracter trai ts of th e C + + s tandard li brary als o defi ne fu ncti onal beh av i or s u ch as com p ari ng , m ov i ng , and fi ndi ng ch aracters . A nd by rep laci ng th es e trai ts you can defi ne s tri ng clas s es th at beh av e i n a cas e-i ns ens i ti v e m anner (s ee Secti on 11.2.14 i n [J os u tti s StdL i b] ) wh i le k eep i ng th e s am e ch aracter typ e. T h u s , alth ou g h th ey are called tr ai ts , th ey h av e s om e p rop erti es as s oci ated wi th p oli ci es .

15.1.6 Member Templates versus Template Template Parameters

T o i m p lem ent an accu m u lati on p oli cy we ch os e to ex p res s SumPolicy and MultPolicy as ordi nary clas s es wi th a m em ber tem p late. A n alternati v e cons i s ts of des i g ni ng th e p oli cy clas s i nterface u s i ng clas s tem p lates , wh i ch are th en u s ed as tem p late tem p late arg u m ents . F or ex am p le, we cou ld rewri te SumPolicy as a tem p late:

// traits/sumpolicy2.hpp #ifndef SUMPOLICY_HPP #define SUMPOLICY_HPP template <typename T1, typename T2> class SumPolicy { public: static void accumulate (T1& total, T2 const & value) { total += value; } }; #endif // SUMPOLICY_HPP

T h e i nterface of Accum can th en be adap ted to u s e a tem p late tem p late

Page 312: CPlusPlus Templates The Complete Guide

p aram eter:

// traits/accum8.hpp #ifndef ACCUM_HPP #define ACCUM_HPP #include "accumtraits4.hpp" #include "sumpolicy2.hpp" template <typename T, template<typename,typename> class Policy = SumPolicy, typename Traits = AccumulationTraits<T> > class Accum { public: typedef typename Traits::AccT AccT; static AccT accum (T const* beg, T const* end) { AccT total = Traits::zero(); while (beg != end) { Policy<AccT,T>::accumulate(total, *beg); ++beg; } return total; } }; #endif // ACCUM_HPP

T h e s am e trans form ati on can be ap p li ed to th e trai ts p aram eter. (O th er v ari ati ons on th i s th em e are p os s i ble: F or ex am p le, i ns tead of ex p li ci tly p as s i ng th e AccT typ e to th e p oli cy typ e, i t m ay be adv antag eou s to p as s th e accu m u lati on trai t and h av e th e p oli cy determ i ne th e typ e of i ts res u lt from a trai ts p aram eter.)

T h e m aj or adv antag e of acces s i ng p oli cy clas s es th rou g h tem p late tem p late p aram eters i s th at i t m ak es i t eas i er to h av e a p oli cy clas s carry wi th i t s om e s tate i nform ati on (th at i s , s tati c data m em bers ) wi th a typ e th at dep ends on th e tem p late p aram eters . (I n ou r fi rs t ap p roach th e s tati c data m em bers wou ld h av e to be em bedded i n a m em ber clas s tem p late.)

H owev er, a downs i de of th e tem p late tem p late p aram eter ap p roach i s th at p oli cy clas s es m u s t now be wri tten as tem p lates , wi th th e ex act s et of tem p late p aram eters defi ned by ou r i nterface. T h i s , u nfortu nately, di s allows any addi ti onal tem p late p aram eters i n ou r p oli ci es . F or ex am p le, we m ay want to add a B oolean nontyp e tem p late p aram eter to SumPolicy th at s elects wh eth er s u m m ati on s h ou ld h ap p en wi th th e += op erator or wh eth er + only s h ou ld be u s ed. I n th e p rog ram u s i ng a m em ber tem p late we can s i m p ly rewri te SumPolicy as a tem p late:

// traits/sumpolicy3.hpp

Page 313: CPlusPlus Templates The Complete Guide

#ifndef SUMPOLICY_HPP #define SUMPOLICY_HPP template<bool use_compound_op = true> class SumPolicy { public: template<typename T1, typename T2> static void accumulate (T1& total, T2 const & value) { total += value; } }; template<> class SumPolicy<false> { public: template<typename T1, typename T2> static void accumulate (T1& total, T2 const & value) { total = total + value; } }; #endif // SUMPOLICY_HPP

W i th i m p lem entati on of Accum u s i ng tem p late tem p late p aram eters s u ch an adap tati on i s no long er p os s i ble.

15.1.7 Combining Multiple Policies and/or Traits

A s ou r dev elop m ent h as s h own, trai ts and p oli ci es don' t enti rely do away wi th h av i ng m u lti p le tem p late p aram eters . H owev er, th ey do redu ce th ei r nu m ber to s om eth i ng m anag eable. A n i nteres ti ng q u es ti on, th en, i s h ow to order s u ch m u lti p le p aram eters .

A s i m p le s trateg y i s to order th e p aram eters accordi ng to th e i ncreas i ng li k eli h ood of th ei r defau lt v alu e to be s elected. T yp i cally, th i s wou ld m ean th at th e trai ts p aram eters follow th e p oli cy p aram eters becau s e th e latter are m ore often ov erri dden i n cli ent code. (T h e obs erv ant reader m ay h av e noti ced th i s s trateg y i n ou r dev elop m ent.)

I f we are wi lli ng to add a s i g ni fi cant am ou nt of com p lex i ty to ou r code, an alternati v e ex i s ts th at es s enti ally allows u s to s p eci fy th e nondefau lt arg u m ents i n any order. R efer to Secti on 16.1 on p ag e 28 5 for detai ls . C h ap ter 13 als o di s cu s s es p otenti al fu tu re tem p late featu res th at cou ld s i m p li fy th e res olu ti on of th i s as p ect of tem p late des i g n.

15.1.8 Accumulation with General Iterators

B efore we end th i s i ntrodu cti on to trai ts and p oli ci es , i t i s i ns tru cti v e to look at one v ers i on of accum() th at adds th e cap abi li ty to h andle g enerali z ed i terators (rath er th an j u s t p oi nters ), as ex p ected from an i ndu s tri al-s treng th g eneri c com p onent. I nteres ti ng ly, th i s s ti ll allows u s to call accum() wi th p oi nters

Page 314: CPlusPlus Templates The Complete Guide

becau s e th e C + + s tandard li brary p rov i des s o-called i ter ator tr ai ts. (T rai ts are ev erywh ere! ) T h u s , we cou ld h av e defi ned ou r i ni ti al v ers i on of accum() as follows (i g nori ng ou r later refi nem ents ):

// traits/accum0.hpp #ifndef ACCUM_HPP #define ACCUM_HPP #include <iterator> template <typename Iter> inline typename std::iterator_traits<Iter>::value_type accum (Iter start, Iter end) { typedef typename std::iterator_traits<Iter>::value_type VT; VT total = VT(); // assume T() actually creates a zero value while (start != end) { total += *start; ++start; } return total; } #endif // ACCUM_HPP

T h e iterator_traits s tru ctu re encap s u lates all th e relev ant p rop erti es of i terator. B ecau s e a p arti al s p eci ali z ati on for p oi nters ex i s ts , th es e trai ts are conv eni ently u s ed wi th any ordi nary p oi nter typ es . H ere i s h ow a s tandard li brary i m p lem entati on m ay i m p lem ent th i s s u p p ort:

namespace std { template <typename T> struct iterator_traits<T*> { typedef T value_type; typedef ptrdiff_t difference_type; typedef random_access_iterator_tag iterator_category; typedef T* pointer; typedef T& reference; }; }

H owev er, th ere i s no typ e for th e accu m u lati on of v alu es to wh i ch an i terator refers ; h ence we s ti ll need to des i g n ou r own AccumulationTraits.

Page 315: CPlusPlus Templates The Complete Guide

15.2 Type Functions

T h e i ni ti al trai ts ex am p le dem ons trates th at you can defi ne beh av i or th at dep ends on typ es . T h i s i s di fferent from wh at you u s u ally i m p lem ent i n p rog ram s . I n C and C + + , fu ncti ons m ore ex actly can be called v alu e f u n c ti on s: T h ey tak e s om e v alu es as p aram eters and retu rn anoth er v alu e as a res u lt. N ow, wh at we h av e wi th tem p lates are ty pe f u n c ti on s: a fu ncti on th at tak es s om e typ e arg u m ents and p rodu ces a typ e or cons tant as a res u lt.

A v ery u s efu l bu i lt-i n typ e fu ncti on i s sizeof , wh i ch retu rns a cons tant des cri bi ng th e s i z e (i n bytes ) of th e g i v en typ e arg u m ent. C las s tem p lates can als o s erv e as typ e fu ncti ons . T h e p aram eters of th e typ e fu ncti on are th e tem p late p aram eters , and th e res u lt i s ex tracted as a m em ber typ e or m em ber cons tant. F or ex am p le, th e sizeof op erator cou ld be g i v en th e followi ng i nterface:

// traits/sizeof.cpp #include <stddef.h> #include <iostream> template <typename T> class TypeSize { public: static size_t const value = sizeof(T); }; int main() { std::cout << "TypeSize<int>::value = " << TypeSize<int>::value << std::endl; }

I n wh at follows we dev elop a few m ore g eneral-p u rp os e typ e fu ncti ons th at can be u s ed as trai ts clas s es i n th i s way.

15.2.1 Determining Element Types

F or anoth er ex am p le, as s u m e th at we h av e a nu m ber of contai ner tem p lates s u ch as vector<T> , list<T>, and stack<T>. W e want a typ e fu ncti on th at, g i v en s u ch a contai ner typ e, p rodu ces th e elem ent typ e. T h i s can be ach i ev ed u s i ng p arti al s p eci ali z ati on:

// traits/elementtype.cpp #include <vector>

Page 316: CPlusPlus Templates The Complete Guide

#include <list> #include <stack> #include <iostream> #include <typeinfo> template <typename T> class ElementT; // primary template template <typename T> class ElementT<std::vector<T> > { // partial specialization public: typedef T Type; }; template <typename T> class ElementT<std::list<T> > { // partial specialization public: typedef T Type; }; template <typename T> class ElementT<std::stack<T> > { // partial specialization public: typedef T Type; }; template <typename T> void print_element_type (T const & c) { std::cout << "Container of " << typeid(typename ElementT<T>::Type).name() << " elements.\n"; } int main() { std::stack<bool> s; print_element_type(s); }

T h e u s e of p arti al s p eci ali z ati on allows u s to i m p lem ent th i s wi th ou t req u i ri ng th e contai ner typ es to k now abou t th e typ e fu ncti on. I n m any cas es , h owev er, th e typ e fu ncti on i s des i g ned along wi th th e ap p li cable typ es and th e i m p lem entati on can be s i m p li fi ed. F or ex am p le, i f th e contai ner typ es defi ne a m em ber typ e value_type (as th e s tandard contai ners do), we can wri te th e followi ng :

template <typename C> class ElementT { public: typedef typename C::value_type Type; };

T h i s can be th e defau lt i m p lem entati on, and i t does not ex clu de s p eci ali z ati ons for contai ner typ es th at do not h av e an ap p rop ri ate m em ber typ e value_type defi ned. N oneth eles s , i t i s u s u ally adv i s able to p rov i de typ e defi ni ti ons for

Page 317: CPlusPlus Templates The Complete Guide

tem p late typ e p aram eters s o th at th ey can be acces s ed m ore eas i ly i n g eneri c code. T h e followi ng s k etch es th e i dea:

template <typename T1, typename T2, ... > class X { public: typedef T1 … ; typedef T2 … ; … };

H ow i s a typ e fu ncti on u s efu l? I t allows u s to p aram eteri z e a tem p late i n term s of a contai ner typ e, wi th ou t als o req u i ri ng p aram eters for th e elem ent typ e and oth er ch aracteri s ti cs . F or ex am p le, i ns tead of

template <typename T, typename C> T sum_of_elements (C const& c);

wh i ch req u i res s yntax li k e sum_of_elements<int>(list) to s p eci fy th e elem ent typ e ex p li ci tly, we can declare

template<typename C> typename ElementT<C>::Type sum_of_elements (C const& c);

wh ere th e elem ent typ e i s determ i ned from th e typ e fu ncti on.

N ote th at th e trai ts can be i m p lem ented as an ex tens i on to th e ex i s ti ng typ es . T h u s , you can defi ne th es e typ e fu ncti ons ev en for fu ndam ental typ es and typ es of clos ed li brari es .

I n th i s cas e, th e typ e ElementT i s called a trai ts clas s becau s e i t i s u s ed to acces s a trai t of th e g i v en contai ner typ e C (i n g eneral, m ore th an one trai t can be collected i n s u ch a clas s ). T h u s , trai ts clas s es are not li m i ted to des cri bi ng ch aracteri s ti cs of contai ner p aram eters bu t of any k i nd of " m ai n p aram eters ."

15.2.2 Determining Class Types

W i th th e followi ng typ e fu ncti on we can determ i ne wh eth er a typ e i s a clas s typ e:

// traits/isclasst.hpp template<typename T> class IsClassT { private: typedef char One; typedef struct { char a[2]; } Two; template<typename C> static One test(int C::*); template<typename C> static Two test(…);

Page 318: CPlusPlus Templates The Complete Guide

public: enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 }; enum { No = !Yes }; };

T h i s tem p late u s es th e SF I N A E (s u bs ti tu ti on-fai lu re-i s -not-an-error) p ri nci p le of Secti on 8 .3 .1 on p ag e 106. T h e k ey to ex p loi t SF I N A E i s to fi nd a typ e cons tru ct th at i s i nv ali d for fu ncti on typ es bu t not for oth er typ es , or v i ce v ers a. F or clas s typ es we can rely on th e obs erv ati on th at th e p oi nter-to-m em ber typ e cons tru ct int C::* i s v ali d only i f C i s a clas s typ e.

T h e followi ng p rog ram u s es th i s typ e fu ncti on to tes t wh eth er certai n typ es and obj ects are clas s typ es :

// traits/isclasst.cpp #include <iostream> #include "isclasst.hpp" class MyClass { }; struct MyStruct { }; union MyUnion { }; void myfunc() { } enumE{e1}e; // check by passing type as template argument template <typename T> void check() { if (IsClassT<T>::Yes) { std::cout << " IsClassT " << std::endl; } else { std::cout << " !IsClassT " << std::endl; } } // check by passing type as function call argument template <typename T> void checkT (T) { check<T>(); } int main() { std::cout << "int: ";

Page 319: CPlusPlus Templates The Complete Guide

check<int>(); std::cout << "MyClass: "; check<MyClass>(); std::cout << "MyStruct:"; MyStruct s; checkT(s); std::cout << "MyUnion: "; check<MyUnion>(); std::cout << "enum: "; checkT(e); std::cout << "myfunc():"; checkT(myfunc); }

T h e p rog ram h as th e followi ng ou tp u t:

int: !IsClassT MyClass: IsClassT MyStruct: IsClassT MyUnion: IsClassT enum: !IsClassT myfunc(): !IsClassT

15.2.3 References and Qualifiers

C ons i der th e followi ng fu ncti on tem p late defi ni ti on:

// traits/apply1.hpp template <typename T> void apply (T& arg, void (*func)(T)) { func(arg); }

C ons i der als o th e followi ng code th at attem p ts to u s e i t:

// traits/apply1.cpp #include <iostream> #include "apply1.hpp" void incr (int& a) { ++a; } void print (int a) { std::cout << a << std::endl;

Page 320: CPlusPlus Templates The Complete Guide

} int main() { intx=7; apply (x, print); apply (x, incr); }

T h e call

apply (x, print)

i s fi ne. W i th T s u bs ti tu ted by int , th e p aram eter typ es of apply() are int& and void(*)(int), wh i ch corres p onds to th e typ es of th e arg u m ents . T h e call

apply (x, incr)

i s les s s trai g h tforward. M atch i ng th e s econd p aram eter req u i res T to be s u bs ti tu ted wi th int&, and th i s i m p li es th at th e fi rs t p aram eter typ e i s int& &, wh i ch ordi nari ly i s not a leg al C + + typ e. I ndeed, th e ori g i nal C + + s tandard ru led th i s an i nv ali d s u bs ti tu ti on, bu t becau s e of ex am p les li k e th i s , a later tec hn i c al c or r i g en d u m (a s et of s m all correcti ons of th e s tandard; s ee [Standard02] ) m ade T& wi th T s u bs ti tu ted by int& eq u i v alent to int&. [7 ]

[7 ] N ote th at we s ti ll cannot wri te int& &. T h i s i s s i m i lar to th e fact th at T const allows T to be s u bs ti tu ted wi th int const, bu t an ex p li ci t int const const i s not v ali d.

F or C + + com p i lers th at do not i m p lem ent th e newer reference s u bs ti tu ti on ru le, we can create a typ e fu ncti on th at ap p li es th e " reference op erator" i f and only i f th e g i v en typ e i s not already a reference. W e can als o p rov i de th e op p os i te op erati on: Stri p th e reference op erator (i f and only i f th e typ e i s i ndeed a reference). A nd wh i le we are at i t, we can als o add or s tri p const q u ali fi ers . [8 ] A ll th i s i s ach i ev ed u s i ng p arti al s p eci ali z ati on of th e followi ng g eneri c defi ni ti on:

[8 ] T h e h andli ng of volatile and const volatile q u ali fi ers i s om i tted for brev i ty, bu t th ey can be h andled s i m i larly.

// traits/typeop1.hpp template <typename T> class TypeOp { // primary template public: typedef T ArgT; typedef T BareT; typedef T const ConstT; typedef T & RefT;

Page 321: CPlusPlus Templates The Complete Guide

typedef T & RefBareT; typedef T const & RefConstT; };

F i rs t, a p arti al s p eci ali z ati on to catch const typ es :

// traits/typeop2.hpp template <typename T> class TypeOp <T const> { // partial specialization for const types public: typedef T const ArgT; typedef T BareT; typedef T const ConstT; typedef T const & RefT; typedef T & RefBareT; typedef T const & RefConstT; };

T h e p arti al s p eci ali z ati on to catch reference typ es als o catch es reference-to-const typ es . H ence, i t ap p li es th e TypeOp dev i ce recu rs i v ely to obtai n th e bare typ e wh en neces s ary. I n contras t, C + + allows u s to ap p ly th e const q u ali fi er to a tem p late p aram eter th at i s s u bs ti tu ted wi th a typ e th at i s already const. H ence, we need not worry abou t s tri p p i ng th e const q u ali fi er wh en we are g oi ng to reap p ly i t anyway:

// traits/typeop3.hpp template <typename T> class TypeOp <T&> { // partial specialization for references public: typedef T & ArgT; typedef typename TypeOp<T>::BareT BareT; typedef T const ConstT; typedef T & RefT; typedef typename TypeOp<T>::BareT & RefBareT; typedef T const & RefConstT; };

R eferences to void typ es are not allowed. I t i s s om eti m es u s efu l to treat s u ch typ es as p lai n void h owev er. T h e followi ng s p eci ali z ati on tak es care of th i s :

// traits/typeop4.hpp template<> class TypeOp <void> { // full specialization for void public: typedef void ArgT; typedef void BareT; typedef void const ConstT; typedef void RefT; typedef void RefBareT;

Page 322: CPlusPlus Templates The Complete Guide

typedef void RefConstT; };

W i th th i s i n p lace, we can rewri te th e apply tem p late as follows :

template <typename T> void apply (typename TypeOp<T>::RefT arg, void (*func)(T)) { func(arg); }

and ou r ex am p le p rog ram wi ll work as i ntended.

R em em ber th at T can no long er be dedu ced from th e fi rs t arg u m ent becau s e i t now ap p ears i n a nam e q u ali fi er. So T i s dedu ced from th e s econd arg u m ent only, and T i s u s ed to create th e typ e of th e fi rs t p aram eter.

15.2.4 Promotion Traits

So far we h av e s tu di ed and dev elop ed typ e fu ncti ons of a s i ng le typ e: G i v en one typ e, oth er related typ es or cons tants were defi ned. I n g eneral, h owev er, we can dev elop typ e fu ncti ons th at dep end on m u lti p le arg u m ents . O ne ex am p le th at i s v ery u s efu l wh en wri ti ng op erator tem p lates are s o-called pr omoti on tr ai ts. T o m oti v ate th e i dea, let' s wri te a fu ncti on tem p late th at allows u s to add two Array contai ners :

template<typename T> Array<T> operator+ (Array<T> const&, Array<T> const&);

T h i s wou ld be ni ce, bu t becau s e th e lang u ag e allows u s to add a char v alu e to an int v alu e, we really wou ld p refer to allow s u ch m i x ed-typ e op erati ons wi th arrays too. W e are th en faced wi th determ i ni ng wh at th e retu rn typ e of th e res u lti ng tem p late s h ou ld be:

template<typename T1, typename T2> Array<???> operator+ (Array<T1> const&, Array<T2> const&);

A p rom oti on trai ts tem p late allows u s to fi ll i n th e q u es ti on m ark s i n th e p rev i ou s declarati on as follows :

template<typename T1, typename T2> Array<typename Promotion<T1, T2>::ResultT> operator+ (Array<T1> const&, Array<T2> const&);

or, alternati v ely, as follows :

Page 323: CPlusPlus Templates The Complete Guide

template<typename T1, typename T2> typename Promotion<Array<T1>, Array<T2> >::ResultT operator+ (Array<T1> const&, Array<T2> const&);

T h e i dea i s to p rov i de a larg e nu m ber of s p eci ali z ati ons of th e tem p late Promotion to create a typ e fu ncti on th at m atch es ou r needs . A noth er ap p li cati on of p rom oti on trai ts was m oti v ated by th e i ntrodu cti on of th e max() tem p late, wh en we want to s p eci fy th at th e m ax i m u m of two v alu es of di fferent typ e s h ou ld h av e th e " th e m ore p owerfu l typ e" (s ee Secti on 2.3 on p ag e 13 ).

T h ere i s no really reli able g eneri c defi ni ti on for th i s tem p late, s o i t m ay be bes t to leav e th e p ri m ary clas s tem p late u ndefi ned:

template<typename T1, typename T2> class Promotion;

A noth er op ti on wou ld be to as s u m e th at i f one of th e typ es i s larg er th an th e oth er, we s h ou ld p rom ote to th at larg er typ e. T h i s can by done by a s p eci al tem p late IfThenElse th at tak es a B oolean nontyp e tem p late p aram eter to s elect one of two typ e p arm eters :

// traits/ifthenelse.hpp #ifndef IFTHENELSE_HPP #define IFTHENELSE_HPP // primary template: yield second or third argument depending on first argument template<bool C, typename Ta, typename Tb> class IfThenElse; // partial specialization: true yields second argument template<typename Ta, typename Tb> class IfThenElse<true, Ta, Tb> { public: typedef Ta ResultT; }; // partial specialization: false yields third argument template<typename Ta, typename Tb> class IfThenElse<false, Ta, Tb> { public: typedef Tb ResultT; }; #endif // IFTHENELSE_HPP

W i th th i s i n p lace, we can create a th ree-way s electi on between T1, T2 , and void, dep endi ng on th e s i z es of th e typ es th at need p rom oti on:

Page 324: CPlusPlus Templates The Complete Guide

// traits/promote1.hpp // primary template for type promotion template<typename T1, typename T2> class Promotion { public: typedef typename IfThenElse<(sizeof(T1)>sizeof(T2)), T1, typename IfThenElse<(sizeof(T1)<sizeof(T2)), T2, void >::ResultT >::ResultT ResultT; };

T h e s i z e-bas ed h eu ri s ti c u s ed i n th e p ri m ary tem p late work s s om eti m es , bu t i t req u i res ch eck i ng . I f i t s elects th e wrong typ e, an ap p rop ri ate s p eci ali z ati on m u s t be wri tten to ov erri de th e s electi on. O n th e oth er h and, i f th e two typ es are i denti cal, we can s afely m ak e i t to be th e p rom oted typ e. A p arti al s p eci ali z ati on tak es care of th i s :

// traits/promote2.hpp // partial specialization for two identical types template<typename T> class Promotion<T,T> { public: typedef T ResultT; };

M any s p eci ali z ati ons are needed to record th e p rom oti on of fu ndam ental typ es . A m acro can redu ce th e am ou nt of s ou rce code s om ewh at:

// traits/promote3.hpp #define MK_PROMOTION(T1,T2,Tr) \ template<> class Promotion<T1, T2> { \ public: \ typedef Tr ResultT; \ }; \ \ template<> class Promotion<T2, T1> { \ public: \ typedef Tr ResultT; \ };

T h e p rom oti ons are th en added as follows :

// traits/promote4.hpp MK_PROMOTION(bool, char, int) MK_PROMOTION(bool, unsigned char, int)

Page 325: CPlusPlus Templates The Complete Guide

MK_PROMOTION(bool, signed char, int) …

T h i s ap p roach i s relati v ely s trai g h tforward, bu t req u i res th e s ev eral doz en p os s i ble com bi nati ons to be enu m erated. V ari ou s alternati v e tech ni q u es ex i s t. F or ex am p le, th e IsFundaT and IsEnumT tem p lates cou ld be adap ted to defi ne th e p rom oti on typ e for i nteg ral and floati ng -p oi nt typ es . P rom oti on wou ld th en need to be s p eci ali z ed only for th e res u lti ng fu ndam ental typ es (and u s er-defi ned typ es , as s h own i n a m om ent).

O nce Promotion i s defi ned for fu ndam ental typ es (and enu m erati on typ es i f des i red), oth er p rom oti on ru les can often be ex p res s ed th rou g h p arti al s p eci ali z ati on. F or ou r Array ex am p le:

// traits/promotearray.hpp template<typename T1, typename T2> class Promotion<Array<T1>, Array<T2> > { public: typedef Array<typename Promotion<T1,T2>::ResultT> ResultT; }; template<typename T> class Promotion<Array<T>, Array<T> > { public: typedef Array<typename Promotion<T,T>::ResultT> ResultT; };

T h i s las t p arti al s p eci ali z ati on des erv es s om e s p eci al attenti on. A t fi rs t i t m ay s eem th at th e earli er p arti al s p eci ali z ati on for i denti cal typ es (Promotion<T,T>) already tak es care of th i s cas e. U nfortu nately, th e p arti al s p eci ali z ati on Promotion<Array<T1>, Array<T2> > i s nei th er m ore nor les s s p eci ali z ed th an th e p arti al s p eci ali z ati on Promotion<T,T> (s ee als o Secti on 12.4 on p ag e 200). [9 ] T o av oi d tem p late s electi on am bi g u i ty, th e las t p arti al s p eci ali z ati on was added. I t i s m ore s p eci ali z ed th an ei th er of th e p rev i ou s two p arti al s p eci ali z ati ons .

[9 ] T o s ee th i s , try to fi nd a s u bs ti tu ti on of T th at m ak es th e latter becom e th e form er, or s u bs ti tu ti ons for T1 and T2 th at m ak e th e form er becom e th e latter.

M ore s p eci ali z ati ons and p arti al s p eci ali z ati ons of th e Promotion tem p late can be added as m ore typ es are added for wh i ch a concep t p rom oti on m ak es s ens e.

Page 326: CPlusPlus Templates The Complete Guide

15.3 Policy Traits

So far, ou r ex am p les of trai ts tem p lates h av e been u s ed to determ i ne p rop erti es of tem p late p aram eters : wh at s ort of typ e th ey rep res ent, to wh i ch typ e th ey s h ou ld p rom ote i n m i x ed-typ e op erati ons , and s o forth . Su ch trai ts are called pr oper ty tr ai ts.

I n contras t, s om e trai ts defi ne h ow s om e typ es s h ou ld be treated. W e call th em poli c y tr ai ts. T h i s i s rem i ni s cent of th e p rev i ou s ly di s cu s s ed concep t of p oli cy clas s es (and we already p oi nted ou t th at th e di s ti ncti on between trai ts and p oli ci es i s not enti rely clear), bu t p oli cy trai ts tend to be m ore u ni q u e p rop erti es as s oci ated wi th a tem p late p aram eter (wh ereas p oli cy clas s es are u s u ally i ndep endent of oth er tem p late p aram eters ).

A lth ou g h p rop erty trai ts can often be i m p lem ented as typ e fu ncti ons , p oli cy trai ts u s u ally encap s u late th e p oli cy i n m em ber fu ncti ons . A s a fi rs t i llu s trati on, let' s look at a typ e fu ncti on th at defi nes a p oli cy for p as s i ng read-only p aram eters .

15.3.1 Read-only Parameter Types

I n C and C + + , fu ncti on call arg u m ents are p as s ed " by v alu e" by defau lt. T h i s m eans th at th e v alu es of th e arg u m ents com p u ted by th e caller are cop i ed to locati ons controlled by th e callee. M os t p rog ram m ers k now th at th i s can be cos tly for larg e s tru ctu res and th at for s u ch s tru ctu res i t i s ap p rop ri ate to p as s th e arg u m ents " by reference-to-const " (or " by p oi nter-to-const" i n C ). F or s m aller s tru ctu res , th e p i ctu re i s not always clear, and th e bes t m ech ani s m from a p erform ance p oi nt of v i ew dep ends on th e ex act arch i tectu re for wh i ch th e code i s bei ng wri tten. T h i s i s not s o cri ti cal i n m os t cas es , bu t s om eti m es ev en th e s m all s tru ctu res m u s t be h andled wi th care.

W i th tem p lates , of cou rs e, th i ng s g et a li ttle m ore deli cate: W e don' t k now a p ri ori h ow larg e th e typ e s u bs ti tu ted for th e tem p late p aram eter wi ll be. F u rth erm ore, th e deci s i on does n' t dep end j u s t on s i z e: A s m all s tru ctu re m ay com e wi th an ex p ens i v e cop y cons tru ctor th at wou ld s ti ll j u s ti fy p as s i ng read-only p aram eters " by reference-to-const."

A s h i nted at earli er, th i s p roblem i s conv eni ently h andled u s i ng a p oli cy trai ts tem p late th at i s a typ e fu ncti on: T h e fu ncti on m ap s an i ntended arg u m ent typ e T onto th e op ti m al p aram eter typ e T or T const&. A s a fi rs t ap p rox i m ati on, th e p ri m ary tem p late can u s e " by v alu e" p as s i ng for typ es no larg er th an two p oi nters and " by reference-to-const " for ev eryth i ng els e:

Page 327: CPlusPlus Templates The Complete Guide

template<typename T> class RParam { public: typedef typename IfThenElse<sizeof(T)<=2*sizeof(void*), T, T const&>::ResultT Type; };

O n th e oth er h and, contai ner typ es for wh i ch sizeof retu rns a s m all v alu e m ay i nv olv e ex p ens i v e cop y cons tru ctors . So we m ay need m any s p eci ali z ati ons and p arti al s p eci ali z ati ons , s u ch as th e followi ng :

template<typename T> class RParam<Array<T> > { public: typedef Array<T> const& Type; };

B ecau s e s u ch typ es are com m on i n C + + , i t m ay be s afer to m ark nonclas s typ es " by v alu e" i n th e p ri m ary tem p late and th en s electi v ely add th e clas s typ es wh en p erform ance cons i derati ons di ctate i t (th e p ri m ary tem p late u s es IsClassT<> from p ag e 266 to i denti fy clas s typ es ):

// traits/rparam.hpp #ifndef RPARAM_HPP #define RPARAM_HPP #include "ifthenelse.hpp" #include "isclasst.hpp" template<typename T> class RParam { public: typedef typename IfThenElse<IsClassT<T>::No, T, T const&>::ResultT Type; }; #endif // RPARAM_HPP

E i th er way, th e p oli cy can now be centrali z ed i n th e trai ts tem p late defi ni ti on, and cli ents can ex p loi t i t to g ood effect. F or ex am p le, let' s s u p p os e we h av e two clas s es , wi th one clas s s p eci fyi ng th at calli ng by v alu e i s better for read-only arg u m ents :

// traits/rparamcls.hpp #include <iostream> #include "rparam.hpp" class MyClass1 {

Page 328: CPlusPlus Templates The Complete Guide

public: MyClass1 () { } MyClass1 (MyClass1 const&) { std::cout << "MyClass1 copy constructor called\n"; } }; class MyClass2 { public: MyClass2 () { } MyClass2 (MyClass2 const&) { std::cout << "MyClass2 copy constructor called\n"; } }; // pass MyClass2 objects with RParam<> by value template<> class RParam<MyClass2> { public: typedef MyClass2 Type; };

N ow, you can declare fu ncti ons th at u s e RParam<> for read-only arg u m ents and call th es e fu ncti ons :

// traits/rparam1.cpp #include "rparam.hpp" #include "rparamcls.hpp" // function that allows parameter passing by value or by reference template <typename T1, typename T2> void foo (typename RParam<T1>::Type p1, typename RParam<T2>::Type p2) { … } int main() { MyClass1 mc1; MyClass2 mc2; foo<MyClass1,MyClass2>(mc1,mc2); }

T h ere are u nfortu nately s om e s i g ni fi cant downs i des to u s i ng RParam. F i rs t, th e fu ncti on declarati on i s s i g ni fi cantly m ore m es s . Second, and p erh ap s m ore obj ecti onable, i s th e fact th at a fu ncti on li k e foo() cannot be called wi th arg u m ent dedu cti on becau s e th e tem p late p aram eter ap p ears only i n th e q u ali fi ers of th e fu ncti on p aram eters . C all s i tes m u s t th erefore s p eci fy ex p li ci t tem p late arg u m ents .

A n u nwi eldy work arou nd for th i s op ti on i s th e u s e of an i nli ne wrap p er fu ncti on tem p late, bu t i t as s u m es th e i nli ne fu ncti on wi ll be eli ded by th e com p i ler. F or

Page 329: CPlusPlus Templates The Complete Guide

ex am p le:

// traits/rparam2.cpp #include "rparam.hpp" #include "rparamcls.hpp" // function that allows parameter passing by value or by reference template <typename T1, typename T2> void foo_core (typename RParam<T1>::Type p1, typename RParam<T2>::Type p2) { … } // wrapper to avoid explicit template parameter passing template <typename T1, typename T2> inline void foo (T1 const & p1, T2 const & p2) { foo_core<T1,T2>(p1,p2); } int main() { MyClass1 mc1; MyClass2 mc2; foo(mc1,mc2); // same as foo_core<MyClass1,MyClass2>(mc1,mc2) }

15.3.2 Copying, Swapping, and Moving

T o conti nu e th e th em e of p erform ance, we can i ntrodu ce a p oli cy trai ts tem p late to s elect th e bes t op erati on to cop y, s wap , or m ov e elem ents of a certai n typ e.

P res u m ably, cop yi ng i s cov ered by th e cop y cons tru ctor and th e cop y-as s i g nm ent op erator. T h i s i s defi ni tely tru e for a s i ng le elem ent, bu t i t i s not i m p os s i ble th at cop yi ng a larg e nu m ber of i tem s of a g i v en typ e can be done s i g ni fi cantly m ore effi ci ently th an by rep eatedly i nv ok i ng th e cons tru ctor or as s i g nm ent op erati ons of th at typ e.

Si m i larly, certai n typ es can be s wap p ed or m ov ed m u ch m ore effi ci ently th an a g eneri c s eq u ence of th e clas s i c form :

T tmp(a); a = b; b = tmp;

C ontai ner typ es typ i cally fall i n th i s categ ory. I n fact, i t occas i onally h ap p ens th at cop yi ng i s not allowed, wh ereas s wap p i ng or m ov i ng i s fi ne. I n th e ch ap ter on u ti li ti es , we dev elop a s o-called smar t poi n ter wi th th i s p rop erty (s ee C h ap ter

Page 330: CPlusPlus Templates The Complete Guide

20).

H ence, i t can be u s efu l to centrali z e deci s i ons i n th i s area i n a conv eni ent trai ts tem p late. F or th e g eneri c defi ni ti on, we wi ll di s ti ng u i s h clas s typ es from nonclas s typ es becau s e we need not worry abou t u s er-defi ned cop y cons tru ctors and cop y as s i g nm ents for th e latter. T h i s ti m e we u s e i nh eri tance to s elect between two trai ts i m p lem entati ons :

// traits/csmtraits.hpp template <typename T> class CSMtraits : public BitOrClassCSM<T, IsClassT<T>::No > { };

T h e i m p lem entati on i s th u s com p letely deleg ated to s p eci ali z ati ons of BitOrClassCSM<> (" CSM" s tands for " cop y, s wap , m ov e" ). T h e s econd tem p late p aram eter i ndi cates wh eth er bi twi s e cop yi ng can be u s ed s afely to i m p lem ent th e v ari ou s op erati ons . T h e g eneri c defi ni ti on cons erv ati v ely as s u m es th at clas s typ es can not be bi twi s ed cop i ed s afely, bu t i f a certai n clas s typ e i s k nown to be a plai n old d ata ty pe (or PO D ), th e CSMtraits clas s i s eas i ly s p eci ali z ed for better p erform ance:

template<> class CSMtraits<MyPODType> : public BitOrClassCSM<MyPODType, true> { };

T h e BitOrClassCSM tem p late cons i s ts , by defau lt, of two p arti al s p eci ali z ati ons . T h e p ri m ary tem p late and th e s afe p arti al s p eci ali z ati on th at does n' t cop y bi twi s e i s as follows :

// traits/csm1.hpp #include <new> #include <cassert> #include <stddef.h> #include "rparam.hpp" // primary template template<typename T, bool Bitwise> class BitOrClassCSM; // partial specialization for safe copying of objects template<typename T> class BitOrClassCSM<T, false> { public: static void copy (typename RParam<T>::ResultT src, T* dst) { // copy one item onto another one *dst = src; }

Page 331: CPlusPlus Templates The Complete Guide

static void copy_n (T const* src, T* dst, size_t n) { // copy n items onto n other ones for (size_tk=0;k<n; ++k) { dst[k] = src[k]; } } static void copy_init (typename RParam<T>::ResultT src, void* dst) { // copy an item onto uninitialized storage ::new(dst) T(src); } static void copy_init_n (T const* src, void* dst, size_t n) { // copy n items onto uninitialized storage for (size_tk=0;k<n; ++k) { ::new((void*)((char*)dst+k)) T(src[k]); } } static void swap (T* a, T* b) { // swap two items T tmp(a); *a = *b; *b = tmp; } static void swap_n (T* a, T* b, size_t n) { // swap n items for (size_tk=0;k<n; ++k) { T tmp(a[k]); a[k] = b[k]; b[k] = tmp; } } static void move (T* src, T* dst) { // move one item onto another assert(src != dst); *dst = *src; src->~T(); } static void move_n (T* src, T* dst, size_t n) { // move n items onto n other ones assert(src != dst); for (size_tk=0;k<n; ++k) { dst[k] = src[k]; src[k].~T(); } } static void move_init (T* src, void* dst) { // move an item onto uninitialized storage assert(src != dst); ::new(dst) T(*src); src->~T(); } static void move_init_n (T const* src, void* dst, size_t n) {

Page 332: CPlusPlus Templates The Complete Guide

// move n items onto uninitialized storage assert(src != dst); for (size_tk=0;k<n; ++k) { ::new((void*)((char*)dst+k)) T(src[k]); src[k].~T(); } } };

T h e term mov e h ere m eans th at a v alu e i s trans ferred from one p lace to anoth er, and h ence th e ori g i nal v alu e no long er ex i s ts (or, m ore p reci s ely, th e ori g i nal locati on m ay h av e been des troyed). T h e c opy op erati on, on th e oth er h and, g u arantees th at both th e s ou rce and des ti nati on locati ons h av e v ali d and i denti cal v alu es . T h i s s h ou ld not be confu s ed wi th th e di s ti ncti on between memcpy() and memmove(), wh i ch i s m ade i n th e s tandard C li brary: I n th at cas e, mov e i m p li es th at th e s ou rce and des ti nati on areas m ay ov erlap , wh ereas for c opy th ey do not. I n ou r i m p lem entati on of th e C SM trai ts , we always as s u m e th at th e s ou rces and des ti nati ons do not ov erlap . I n an i ndu s tri al-s treng th li brary, a shi f t op erati on s h ou ld p robably be added to ex p res s th e p oli cy for s h i fti ng obj ects wi th i n a conti g u ou s area of m em ory (th e op erati on enabled by memmove()). W e om i t i t for th e s ak e of s i m p li ci ty.

T h e m em ber fu ncti ons of ou r p oli cy trai ts tem p late are all s tati c. T h i s i s alm os t always th e cas e, becau s e th e m em ber fu ncti ons are m eant to ap p ly to obj ects of th e p aram eter typ e rath er th an obj ects of th e trai ts clas s typ e.

T h e oth er p arti al s p eci ali z ati on i m p lem ents th e trai ts for bi twi s e typ es th at can be cop i ed:

// traits/csm2.hpp #include <cstring> #include <cassert> #include <stddef.h> #include "csm1.hpp" // partial specialization for fast bitwise copying of objects template <typename T> class BitOrClassCSM<T,true> : public BitOrClassCSM<T,false> { public: static void copy_n (T const* src, T* dst, size_t n) { // copy n items onto n other ones std::memcpy((void*)dst, (void*)src, n); } static void copy_init_n (T const* src, void* dst, size_t n) { // copy n items onto uninitialized storage std::memcpy(dst, (void*)src, n); } static void move_n (T* src, T* dst, size_t n) { // move n items onto n other ones

Page 333: CPlusPlus Templates The Complete Guide

assert(src != dst); std::memcpy((void*)dst, (void*)src, n); } static void move_init_n (T const* src, void* dst, size_t n) { // move n items onto uninitialized storage assert(src != dst); std::memcpy(dst, (void*)src, n); } };

W e u s ed anoth er lev el of i nh eri tance to s i m p li fy th e i m p lem entati on of th e trai ts for bi twi s e typ es th at can be cop i ed. T h i s i s certai nly not th e only p os s i ble i m p lem entati on. I n fact, for p arti cu lar p latform s i t m ay be des i rable to i ntrodu ce s om e i nli ne as s em bly (for ex am p le, to tak e adv antag e of h ardware s wap op erati ons ).

Page 334: CPlusPlus Templates The Complete Guide

15.4 Afternotes

N ath an M yers was th e fi rs t to form ali z e th e i dea of trai ts p aram eters . H e ori g i nally p res ented th em to th e C + + s tandardi z ati on com m i ttee as a v eh i cle to defi ne h ow ch aracter typ es s h ou ld be treated i n s tandard li brary com p onents (for ex am p le, i np u t and ou tp u t s tream s ). A t th at ti m e h e called th em b ag g ag e templates and noted th at th ey contai ned trai ts . H owev er, s om e C + + com m i ttee m em bers di d not li k e th e term b ag g ag e , and th e nam e tr ai ts was p rom oted i ns tead. T h e latter term h as been wi dely u s ed s i nce th en.

C li ent code u s u ally does not deal wi th trai ts at all: T h e defau lt trai ts clas s es s ati s fy th e m os t com m on needs , and becau s e th ey are defau lt tem p late arg u m ents , th ey need not ap p ear i n th e cli ent s ou rce at all. T h i s arg u es i n fav or of long des cri p ti v e nam es for th e defau lt trai ts tem p lates . W h en cli ent code does adap t th e beh av i or of a tem p late by p rov i di ng a cu s tom trai ts arg u m ent, i t i s g ood p racti ce to typ edef th e res u lti ng s p eci ali z ati ons to a nam e th at i s ap p rop ri ate for th e cu s tom beh av i or. I n th i s cas e th e trai ts clas s can be g i v en a long des cri p ti v e nam e wi th ou t s acri fi ci ng too m u ch s ou rce es tate.

O u r di s cu s s i on h as p res ented trai ts tem p lates as bei ng clas s tem p lates ex clu s i v ely. Stri ctly s p eak i ng , th i s does not need to be th e cas e. I f only a s i ng le p oli cy trai t needs to be p rov i ded, i t cou ld be p as s ed as an ordi nary fu ncti on tem p late. F or ex am p le:

template <typename T, void (*Policy)(T const&, T const&)> class X;

H owev er, th e ori g i nal g oal of trai ts was to redu ce th e bag g ag e of s econdary tem p late arg u m ents , wh i ch i s not ach i ev ed i f only a s i ng le trai t i s encap s u lated i n a tem p late p aram eter. T h i s j u s ti fi es M yers ' s p reference for th e term b ag g ag e as a collecti on of trai ts . W e rev i s i t th e p roblem of p rov i di ng an orderi ng cri teri on i n C h ap ter 22.

T h e s tandard li brary defi nes a clas s tem p late std::char_traits, wh i ch i s u s ed as a p oli cy trai ts p aram eter. T o adap t alg ori th m s eas i ly to th e k i nd of ST L i terators for wh i ch th ey are u s ed, a v ery s i m p le std::iterator_traits p rop erty trai ts tem p late i s p rov i ded (and u s ed i n s tandard li brary i nterfaces ). T h e tem p late std::numeric_limits can als o be u s efu l as a p rop erty trai ts tem p late, bu t i t i s not v i s i bly u s ed i n th e s tandard li brary p rop er. T h e clas s tem p lates std::unary_function and std::binary_function fall i n th e s am e categ ory and are v ery s i m p le typ e fu ncti ons : T h ey only typ edef th ei r

Page 335: CPlusPlus Templates The Complete Guide

arg u m ents to m em ber nam es th at m ak e s ens e for fu nctors (als o k nown as f u n c ti on ob j ec ts , s ee C h ap ter 22). L as tly, m em ory allocati on for th e s tandard contai ner typ es i s h andled u s i ng a p oli cy trai ts clas s . T h e tem p late std::allocator i s p rov i ded as th e s tandard i tem for th i s p u rp os e.

P oli cy clas s es h av e ap p arently been dev elop ed by m any p rog ram m ers and a few au th ors . A ndrei A lex andres cu m ade th e term poli c y c lasses p op u lar, and h i s book M od er n C++ D esi g n cov ers th em i n m ore detai l th an ou r bri ef s ecti on (s ee [A lex andres cu D es i g n] ).

Page 336: CPlusPlus Templates The Complete Guide

Chapter 16. Templates and Inheritance

A p ri ori , th ere m i g h t be no reas on to th i nk th at tem p lates and i nh eri tance i nteract i n i nteres ti ng ways . I f anyth i ng , we k now from C h ap ter 9 th at deri v i ng from dep endent bas e clas s es forces u s to deal carefu lly wi th u nq u ali fi ed nam es . H owev er, i t tu rns ou t th at s om e i nteres ti ng tech ni q u es m ak e u s e of s o-called par ameter i z ed i n her i tan c e. I n th i s ch ap ter we des cri be a few of th es e tech ni q u es .

Page 337: CPlusPlus Templates The Complete Guide

16.1 Named Template Arguments

V ari ou s tem p late tech ni q u es s om eti m es cau s e a clas s tem p late to end u p wi th m any di fferent tem p late typ e p aram eters . H owev er, m any of th es e p aram eters often h av e reas onable defau lt v alu es . A natu ral way to defi ne s u ch a clas s tem p late m ay look as follows :

template<typename Policy1 = DefaultPolicy1, typename Policy2 = DefaultPolicy2, typename Policy3 = DefaultPolicy3, typename Policy4 = DefaultPolicy4> class BreadSlicer { … };

P res u m ably, s u ch a tem p late can often be u s ed wi th th e defau lt tem p late arg u m ent v alu es u s i ng th e s yntax BreadSlicer<>. H owev er, i f a nondefau lt arg u m ent m u s t be s p eci fi ed, all p recedi ng arg u m ents m u s t be s p eci fi ed too (ev en th ou g h th ey m ay h av e th e defau lt v alu e).

C learly, i t wou ld be attracti v e to be able to u s e a cons tru ct ak i n to BreadSlicer<Policy3 = Custom> rath er th an BreadSlicer<DefaultPolicy1, DefaultPolicy2, Custom> as i s th e cas e ri g h t now. I n wh at follows we dev elop a tech ni q u e to enable alm os t ex actly th at. [1]

[1] N ote th at a s i m i lar lang u ag e ex tens i on for fu ncti on call arg u m ents was p rop os ed (and rej ected) earli er i n th e C + + s tandardi z ati on p roces s (s ee Secti on 13 .9 on p ag e 216 for detai ls ).

O u r tech ni q u e cons i s ts of p laci ng th e defau lt typ e v alu es i n a bas e clas s and ov erri di ng s om e of th em th rou g h deri v ati on. I ns tead of di rectly s p eci fyi ng th e typ e arg u m ents , we p rov i de th em th rou g h h elp er clas s es . F or ex am p le, we cou ld wri te BreadSlicer<Policy3_is<Custom> >. B ecau s e each tem p late arg u m ent can des cri be any of th e p oli ci es , th e defau lts cannot be di fferent. I n oth er words , at a h i g h lev el ev ery tem p late p aram eter i s eq u i v alent:

template <typename PolicySetter1 = DefaultPolicyArgs, typename PolicySetter2 = DefaultPolicyArgs, typename PolicySetter3 = DefaultPolicyArgs, typename PolicySetter4 = DefaultPolicyArgs> class BreadSlicer { typedef PolicySelector<PolicySetter1, PolicySetter2, PolicySetter3, PolicySetter4> Policies;

Page 338: CPlusPlus Templates The Complete Guide

// use Policies::P1, Policies::P2, … to refer to the various policies … };

T h e rem ai ni ng ch alleng e i s to wri te th e PolicySelector tem p late. I t h as to m erg e th e di fferent tem p late arg u m ents i nto a s i ng le typ e th at ov erri des defau lt typ edef m em bers wi th wh i ch ev er non-defau lts were s p eci fi ed. T h i s m erg i ng can be ach i ev ed u s i ng i nh eri tance:

// PolicySelector<A,B,C,D> creates A,B,C,D as base classes // Discriminator<> allows having even the same base class more than once template<typename Base, int D> class Discriminator : public Base { }; template <typename Setter1, typename Setter2, typename Setter3, typename Setter4> class PolicySelector : public Discriminator<Setter1,1>, public Discriminator<Setter2,2>, public Discriminator<Setter3,3>, public Discriminator<Setter4,4> { };

N ote th e u s e of an i nterm edi ate Discriminator tem p late. I t i s needed to allow th e v ari ou s Setter typ es to be i denti cal. (Y ou cannot h av e m u lti p le di rect bas e clas s es of th e s am e typ e. I ndi rect bas e clas s es , on th e oth er h and, can h av e typ es th at are i denti cal to th os e of oth er bas es .)

A s annou nced earli er, we' re collecti ng th e defau lts i n a bas e clas s :

// name default policies as P1, P2, P3, P4 class DefaultPolicies { public: typedef DefaultPolicy1 P1; typedef DefaultPolicy2 P2; typedef DefaultPolicy3 P3; typedef DefaultPolicy4 P4; };

H owev er, we m u s t be carefu l to av oi d am bi g u i ti es i f we end u p i nh eri ti ng m u lti p le ti m es from th i s bas e clas s . T h erefore, we ens u re th at th e bas e clas s i s i nh eri ted v i rtu ally:

// class to define a use of the default policy values // avoids ambiguities if we derive from DefaultPolicies more than once class DefaultPolicyArgs : virtual public DefaultPolicies { };

Page 339: CPlusPlus Templates The Complete Guide

F i nally, we als o need s om e tem p lates to ov erri de th e defau lt p oli cy v alu es :

template <typename Policy> class Policy1_is : virtual public DefaultPolicies { public: typedef Policy P1; // overriding typedef }; template <typename Policy> class Policy2_is : virtual public DefaultPolicies { public: typedef Policy P2; // overriding typedef }; template <typename Policy> class Policy3_is : virtual public DefaultPolicies { public: typedef Policy P3; // overriding typedef }; template <typename Policy> class Policy4_is : virtual public DefaultPolicies { public: typedef Policy P4; // overriding typedef };

W i th all th i s i n p lace, ou r des i red obj ecti v e i s ach i ev ed. N ow let' s look at wh at we h av e by ex am p le. L et' s i ns tanti ate a BreadSlicer<> as follows :

BreadSlicer<Policy3_is<CustomPolicy> > bc;

F or th i s B readSli cer< > th e typ e P oli ci es i s defi ned as

PolicySelector<Policy3_is<CustomPolicy>, DefaultPolicyArgs, DefaultPolicyArgs, DefaultPolicyArgs>

W i th th e h elp of th e Discriminator<> clas s tem p lates th i s res u lts i n a h i erarch y, i n wh i ch all tem p late arg u m ents are bas e clas s es (s ee F i g u re 16.1). T h e i m p ortant p oi nt i s th at th es e bas e clas s es all h av e th e s am e v i rtu al bas e clas s DefaultPolicies, wh i ch defi nes th e defau lt typ es for P1 , P2 , P3 , and P4. H owev er, P3 i s redefi ned i n one of th e deri v ed clas s es —nam ely, i n Policy3_is<>. A ccordi ng to th e s o-called d omi n ati on r u le th i s defi ni ti on h i des th e defi ni ti on of th e bas e clas s . T h u s , th i s i s n ot an am bi g u i ty. [2 ]

[2 ] Y ou can fi nd th e dom i nati on ru le i n Secti on 10.2/6 i n th e C + + Standard (s ee [Standard9 8 ] ) and a di s cu s s i on abou t i t i n Secti on 10.1.1 of [E lli s Strou s tru p A R M ] .

Page 340: CPlusPlus Templates The Complete Guide

Figure 16 .1. R esulting type hierarchy of BreadSlicer<>::Policies

I ns i de th e tem p late BreadSlicer you can refer to th e fou r p oli ci es by u s i ng q u ali fi ed nam es s u ch as Policies::P3. F or ex am p le:

template <... > class BreadSlicer { … public: void print () { Policies::P3::doPrint(); } … };

I n inherit/namedtmpl.cpp you can fi nd th e enti re ex am p le.

W e dev elop ed th e tech ni q u e for fou r tem p late typ e p aram eters , bu t i t obv i ou s ly s cales to any reas onable nu m ber of s u ch p aram eters . N ote th at we nev er actu ally i ns tanti ate obj ects of th e h elp er clas s th at contai n v i rtu al bas es . H ence, th e fact th at th ey are v i rtu al bas es i s not a p erform ance or m em ory cons u m p ti on i s s u e.

Page 341: CPlusPlus Templates The Complete Guide

16.2 The Empty Base Class Optimization (EBCO)

C + + clas s es are often " em p ty, " wh i ch m eans th at th ei r i nternal rep res entati on does not req u i re any bi ts of m em ory at ru n ti m e. T h i s i s th e cas e typ i cally for clas s es th at contai n only typ e m em bers , nonv i rtu al fu ncti on m em bers , and s tati c data m em bers . N ons tati c data m em bers , v i rtu al fu ncti ons , and v i rtu al bas e clas s es , on th e oth er h and, do req u i re s om e m em ory at ru n ti m e.

E v en em p ty clas s es , h owev er, h av e nonz ero s i z e. T ry th e followi ng p rog ram i f you ' d li k e to v eri fy th i s :

// inherit/empty.cpp #include <iostream> class EmptyClass { }; int main() { std::cout << "sizeof(EmptyClass): " << sizeof(EmptyClass) << '\n'; }

F or m any p latform s , th i s p rog ram wi ll p ri nt 1 as s i z e of EmptyClass. A few s ys tem s i m p os e m ore s tri ct ali g nm ent req u i rem ents on clas s typ es and m ay p ri nt anoth er s m all i nteg er (typ i cally, 4).

16.2.1 Layout Principles

T h e des i g ners of C + + h ad v ari ou s reas ons to av oi d z ero-s i z e clas s es . F or ex am p le, an array of z ero-s i z e clas s es wou ld p res u m ably h av e s i z e z ero too, bu t th en th e u s u al p rop erti es of p oi nter ari th m eti c wou ld not ap p ly anym ore. F or ex am p le, let' s as s u m e ZeroSizedT i s a z ero-s i z e typ e:

ZeroSizedT z[10]; … &z[i] - &z[j] // compute distance between pointers/addresses

N orm ally, th e di fference i n th e p rev i ou s ex am p le i s obtai ned by di v i di ng th e nu m ber of bytes between th e two addres s es by th e s i z e of th e typ e to wh i ch i t i s p oi nti ng , bu t wh en th at s i z e i s z ero th i s i s clearly not s ati s factory.

H owev er, ev en th ou g h th ere are no z ero-s i z e typ es i n C + + , th e C + + s tandard does s p eci fy th at wh en an em p ty clas s i s u s ed as a bas e clas s , no s p ace needs to be allocated for i t pr ov i d ed that i t d oes n ot c au se i t to b e alloc ated to the same

Page 342: CPlusPlus Templates The Complete Guide

ad d r ess as an other ob j ec t or su b ob j ec t of the same ty pe. L et' s look at s om e ex am p les to clari fy wh at th i s s o-called empty b ase c lass opti mi z ati on (or E B CO ) m eans i n p racti ce. C ons i der th e followi ng p rog ram :

// inherit/ebco1.cpp #include <iostream> class Empty { typedef int Int; // typedef members don't make a class nonempty }; class EmptyToo : public Empty { }; class EmptyThree : public EmptyToo { }; int main() { std::cout << "sizeof(Empty): " << sizeof(Empty) << '\n'; std::cout << "sizeof(EmptyToo): " << sizeof(EmptyToo) << '\n'; std::cout << "sizeof(EmptyThree): " << sizeof(EmptyThree) << '\n'; }

I f you r com p i ler i m p lem ents th e em p ty bas e op ti m i z ati on, i t wi ll p ri nt th e s am e s i z e for ev ery clas s , bu t none of th es e clas s es h as s i z e z ero (s ee F i g u re 16.2). T h i s m eans th at wi th i n clas s EmptyToo, th e clas s Empty i s not g i v en any s p ace. N ote als o th at an em p ty clas s wi th op ti m i z ed em p ty bas es (and no oth er bas es ) i s als o em p ty. T h i s ex p lai ns wh y clas s EmptyThree can als o h av e th e s am e s i z e as clas s Empty. I f you r com p i ler does not i m p lem ent th e em p ty bas e op ti m i z ati on, i t wi ll p ri nt di fferent s i z es (s ee F i g u re 16.3 ).

Figure 16 .2 . L ayout of EmptyThree b y a compiler that implements the E B C O

Figure 16 .3 . L ayout of EmptyThree b y a compiler that does not implement the E B C O C onsider an ex ample that runs into a constraint of

empty b ase optimiz ation:

Page 343: CPlusPlus Templates The Complete Guide

// inherit/ebco2.cpp #include <iostream> class Empty { typedef int Int; // typedef members don't make a class nonempty }; class EmptyToo : public Empty { }; class NonEmpty : public Empty, public EmptyToo { }; int main() { std::cout << "sizeof(Empty): " << sizeof(Empty) << '\n'; std::cout << "sizeof(EmptyToo): " << sizeof(EmptyToo) << '\n'; std::cout << "sizeof(NonEmpty): " << sizeof(NonEmpty) << '\n'; }

I t m ay com e as a s u rp ri s e th at clas s NonEmpty i s not an em p ty clas s A fter all, i t does not h av e any m em bers and nei th er do i ts bas e clas s es . H owev er, th e bas e clas s es Empty and EmptyToo of NonEmpty cannot be allocated to th e s am e addres s becau s e th i s wou ld cau s e th e bas e clas s Empty of EmptyToo to end u p at th e s am e addres s as th e bas e clas s Empty of clas s NonEmpty. I n oth er words , two s u bobj ects of th e s am e typ e wou ld end u p at th e s am e offs et, and th i s i s not p erm i tted by th e obj ect layou t ru les of C + + . I t m ay be concei v able to deci de th at one of th e Empty bas e s u bobj ects i s p laced at offs et " 0 bytes " and th e oth er at offs et " 1 byte, " bu t th e com p lete NonEmpty obj ect s ti ll cannot h av e a s i z e of one byte becau s e i n an array of two NonEmpty obj ects , an Empty s u bobj ect of th e fi rs t elem ent cannot end u p at th e s am e addres s as an Empty s u bobj ect of th e s econd elem ent (s ee F i g u re 16.4 ).

Figure 16 .4. L ayout of N onE mpty b y a compiler that implements the E B C O

T h e rati onale for th e cons trai nt on em p ty bas e op ti m i z ati on s tem s from th e fact th at i t i s des i rable to be able to com p are wh eth er two p oi nters p oi nt to th e s am e

Page 344: CPlusPlus Templates The Complete Guide

obj ect. B ecau s e p oi nters are nearly always i nternally rep res ented as j u s t addres s es , we m u s t ens u re th at two di fferent addres s es (th at i s , p oi nter v alu es ) corres p ond to two di fferent obj ects .

T h e cons trai nt m ay not s eem v ery s i g ni fi cant. H owev er, i n p racti ce, i t i s often encou ntered becau s e m any clas s es tend to i nh eri t from a s m all s et of em p ty clas s es th at defi ne s om e com m on typ edefs . W h en two s u bobj ects of s u ch clas s es are u s ed i n th e s am e com p lete obj ect, th e op ti m i z ati on i s i nh i bi ted.

16.2.2 Members as Base Classes

T h e em p ty bas e clas s op ti m i z ati on h as no eq u i v alent for data m em bers becau s e (am ong oth er th i ng s ) i t wou ld create s om e p roblem s wi th th e rep res entati on of p oi nters to m em bers . A s a res u lt, i t i s s om eti m es des i rable to i m p lem ent as a (p ri v ate) bas e clas s wh at wou ld at fi rs t s i g h t be th ou g h t of as a m em ber v ari able. H owev er, th i s i s not wi th ou t i ts ch alleng es .

T h e p roblem i s m os t i nteres ti ng i n th e contex t of tem p lates becau s e tem p late p aram eters are often s u bs ti tu ted wi th em p ty clas s typ es , bu t i n g eneral one cannot rely on th i s ru le. I f noth i ng i s k nown abou t a tem p late typ e p aram eter, em p ty bas e op ti m i z ati on cannot eas i ly be ex p loi ted. I ndeed, cons i der th e followi ng tri v i al ex am p le:

template <typename T1, typename T2> class MyClass { private: T1 a; T2 b; … };

I t i s enti rely p os s i ble th at one or both tem p late p aram eters are s u bs ti tu ted by an em p ty clas s typ e. I f th i s i s th e cas e, th en th e rep res entati on of MyClass<T1,T2> m ay be s u bop ti m al and m ay was te a word of m em ory for ev ery i ns tance of a MyClass<T1,T2>.

T h i s can be av oi ded by m ak i ng th e tem p late arg u m ents bas e clas s es i ns tead:

template <typename T1, typename T2> class MyClass : private T1, private T2 { };

H owev er, th i s s trai g h tforward alternati v e h as i ts own s et of p roblem s . I t does n' t work wh en T1 or T2 i s s u bs ti tu ted wi th a nonclas s typ e or wi th a u ni on typ e. I t als o does n' t work wh en th e two p aram eters are s u bs ti tu ted wi th th e s am e typ e (alth ou g h th i s can be addres s ed fai rly eas i ly by addi ng anoth er layer of

Page 345: CPlusPlus Templates The Complete Guide

i nh eri tance; s ee p ag e 28 7 or p ag e 4 4 9 ). H owev er, ev en i f we s ati s factori ly addres s ed th es e p roblem s , a v ery s eri ou s p roblem p ers i s ts : A ddi ng a bas e clas s can fu ndam entally m odi fy th e i nterface of th e g i v en clas s . F or ou r MyClass clas s , th i s m ay not s eem v ery s i g ni fi cant becau s e th ere are v ery few i nterface elem ents to affect, bu t as we s ee later i n th i s ch ap ter, i nh eri ti ng from a tem p late p aram eter can affect wh eth er a m em ber fu ncti on i s v i rtu al. C learly, th i s ap p roach to ex p loi ti ng E B C O i s frau g h t wi th all k i nds of trou ble.

A m ore p racti cal tool can be dev i s ed for th e com m on cas e wh en a tem p late p aram eter i s k nown to be s u bs ti tu ted by clas s typ es only and wh en anoth er m em ber of th e clas s tem p late i s av ai lable. T h e m ai n i dea i s to " m erg e" th e p otenti ally em p ty typ e p aram eter wi th th e oth er m em ber u s i ng E B C O . F or ex am p le, i ns tead of wri ti ng

template <typename CustomClass> class Optimizable { private: CustomClass info; // might be empty void* storage; … };

a tem p late i m p lem enter wou ld u s e th e followi ng :

template <typename CustomClass> class Optimizable { private: BaseMemberPair<CustomClass, void*> info_and_storage; … };

E v en wi th ou t s eei ng th e i m p lem entati on of th e tem p late BaseMemberPair, i t i s clear th at i ts u s e m ak es th e i m p lem entati on of Optimizable m ore v erbos e. H owev er, v ari ou s tem p late li brary i m p lem enters h av e rep orted th at th e p erform ance g ai ns (for th e cli ents of th ei r li brari es ) do j u s ti fy th e added com p lex i ty.

T h e i m p lem entati on of BaseMemberPair can be fai rly com p act:

// inherit/basememberpair.hpp #ifndef BASE_MEMBER_PAIR_HPP #define BASE_MEMBER_PAIR_HPP template <typename Base, typename Member> class BaseMemberPair : private Base { private: Member member;

Page 346: CPlusPlus Templates The Complete Guide

public: // constructor BaseMemberPair (Base const & b, Member const & m) : Base(b), member(m) { } // access base class data via first() Base const& first() const { return (Base const&)*this; } Base& first() { return (Base&)*this; } // access member data via second() Member const& second() const { return this->member; } Member& second() { return this->member; } }; #endif // BASE_MEMBER_PAIR_HPP

A n i m p lem entati on needs to u s e th e m em ber fu ncti ons first() and second() to acces s th e encap s u lated (and p os s i bly s torag e-op ti m i z ed) data m em bers .

Page 347: CPlusPlus Templates The Complete Guide

16.3 The Curiously Recurring Template Pattern (CRTP)

T h i s oddly nam ed p attern refers to a g eneral clas s of tech ni q u es th at cons i s ts of p as s i ng a deri v ed clas s as a tem p late arg u m ent to one of i ts own bas e clas s es . I n i ts s i m p les t form , C + + code for s u ch a p attern look s as follows :

template <typename Derived> class CuriousBase { … }; class Curious : public CuriousBase<Curious> { … };

O u r fi rs t ou tli ne of C R T P s h ows a nondep endent bas e clas s : T h e clas s Curious i s not a tem p late and i s th erefore i m m u ne to s om e of th e nam e v i s i bi li ty i s s u es of dep endent bas e clas s es . H owev er, th i s i s not an i ntri ns i c ch aracteri s ti c of C R T P . I ndeed, we cou ld j u s t as well h av e u s ed th e followi ng alternati v e ou tli ne:

template <typename Derived> class CuriousBase { … }; template <typename T> class CuriousTemplate : public CuriousBase<CuriousTemplate<T> > { … };

F rom th i s ou tli ne, h owev er, i t i s not a far s tretch to p rop os e yet anoth er alternati v e form u lati on, th i s ti m e i nv olv i ng a tem p late tem p late p aram eter:

template <template<typename> class Derived> class MoreCuriousBase { … }; template <typename T> class MoreCurious : public MoreCuriousBase<MoreCurious> { … };

A s i m p le ap p li cati on of C R T P cons i s ts of k eep i ng track of h ow m any obj ects of a certai n clas s typ e were created. T h i s i s eas i ly ach i ev ed by i ncrem enti ng an i nteg ral s tati c data m em ber i n ev ery cons tru ctor and decrem enti ng i t i n th e des tru ctor. H owev er, h av i ng to p rov i de s u ch code i n ev ery clas s i s tedi ou s .

Page 348: CPlusPlus Templates The Complete Guide

I ns tead, we can wri te th e followi ng tem p late:

// inherit/objectcounter.hpp #include <stddef.h> template <typename CountedType> class ObjectCounter { private: static size_t count; // number of existing objects protected: // default constructor ObjectCounter() { ++ObjectCounter<CountedType>::count; } // copy constructor ObjectCounter (ObjectCounter<CountedType> const&) { ++ObjectCounter<CountedType>::count; } // destructor ~ObjectCounter() { --ObjectCounter<CountedType>::count; } public: // return number of existing objects: static size_t live() { return ObjectCounter<CountedType>::count; } }; // initialize counter with zero template <typename CountedType> size_t ObjectCounter<CountedType>::count = 0;

I f we want to cou nt th e nu m ber of li v e (th at i s , not yet des troyed) obj ects for a certai n clas s typ e, i t s u ffi ces to deri v e th e clas s from th e ObjectCounter tem p late. F or ex am p le, we can defi ne and u s e a cou nted s tri ng clas s along th e followi ng li nes :

// inherit/testcounter.cpp #include "objectcounter.hpp" #include <iostream> template <typename CharT> class MyString : public ObjectCounter<MyString<CharT> > { … }; int main() { MyString<char> s1, s2;

Page 349: CPlusPlus Templates The Complete Guide

MyString<wchar_t> ws; std::cout << "number of MyString<char>: " << MyString<char>::live() << std::endl; std::cout << "number of MyString<wchar_t>: " << ws.live() << std::endl; }

I n g eneral, C R T P i s u s efu l to factor ou t i m p lem entati ons of i nterfaces th at can only be m em ber fu ncti ons (for ex am p le, cons tru ctor, des tru ctors , and s u bs cri p t op erators ).

Page 350: CPlusPlus Templates The Complete Guide

16.4 Parameterized Virtuality

C + + allows u s to p aram eteri z e di rectly th ree k i nds of enti ti es th rou g h tem p lates : typ es , cons tants (" nontyp es " ), and tem p lates . H owev er, i ndi rectly, i t als o allows u s to p aram eteri z e oth er attri bu tes s u ch as th e v i rtu ali ty of a m em ber fu ncti on. A s i m p le ex am p le s h ows th i s rath er s u rp ri s i ng tech ni q u e:

// inherit/virtual.cpp #include <iostream> class NotVirtual { }; class Virtual { public: virtual void foo() { } }; template <typename VBase> class Base : private VBase { public: // the virtuality of foo() depends on its declaration // (if any) in the base class VBase void foo() { std::cout << "Base::foo()" << '\n'; } }; template <typename V> class Derived : public Base<V> { public: void foo() { std::cout << "Derived::foo()" << '\n'; } }; int main() { Base<NotVirtual>* p1 = new Derived<NotVirtual>; p1->foo(); // calls Base::foo() Base<Virtual>* p2 = new Derived<Virtual>; p2->foo(); // calls Derived::foo() }

T h i s tech ni q u e can p rov i de a tool to des i g n a clas s tem p late th at i s u s able both to i ns tanti ate concrete clas s es and to ex tend u s i ng i nh eri tance. H owev er, i t i s rarely s u ffi ci ent j u s t to s p ri nk le v i rtu ali ty on s om e m em ber fu ncti ons to obtai n a clas s th at m ak es a g ood bas e clas s for m ore s p eci ali z ed fu ncti onali ty. T h i s s ort of dev elop m ent m eth od req u i res m ore fu ndam ental des i g n deci s i ons . I t i s th erefore

Page 351: CPlusPlus Templates The Complete Guide

u s u ally m ore p racti cal to des i g n two di fferent tools (clas s or clas s tem p late h i erarch i es ) rath er th an tryi ng to i nteg rate th em all i nto one tem p late h i erarch y.

Page 352: CPlusPlus Templates The Complete Guide

16.5 Afternotes

N am ed tem p late arg u m ents are u s ed to s i m p li fy certai n clas s tem p lates i n th e B oos t li brary. B oos t u s es m etap rog ram m i ng to create a typ e wi th p rop erti es s i m i lar to ou r PolicySelector (bu t wi th ou t u s i ng v i rtu al i nh eri tance). T h e s i m p ler alternati v e p res ented h ere was dev elop ed by one of u s (V andev oorde).

C R T P s h av e been i n u s e s i nce at leas t 19 9 1. H owev er, J am es C op li en was fi rs t to des cri be th em form ally as a clas s of s o-called patter n s (s ee [C op li enC R T P ] ). Si nce th en, m any ap p li cati ons of C R T P h av e been p u bli s h ed. T h e p h ras e par ameter i z ed i n her i tan c e i s s om eti m es wrong ly eq u ated wi th C R T P . A s we h av e s h own, C R T P does not req u i re th e deri v ati on to be p aram eteri z ed at all, and m any form s of p aram eteri z ed i nh eri tance do not conform to C R T P . C R T P i s als o s om eti m es confu s ed wi th th e B arton-N ack m an tri ck (s ee Secti on 11.7 on p ag e 17 4 ) becau s e B arton and N ack m an freq u ently u s ed C R T P i n com bi nati on wi th fri end nam e i nj ecti on (and th e latter i s an i m p ortant com p onent of th e B arton-N ack m an tri ck ). O u r ObjectCounter ex am p le i s alm os t i denti cal to a tech ni q u e dev elop ed by Scott M eyers i n [M eyers C ou nti ng ] .

B i ll G i bbons was th e m ai n s p ons or beh i nd th e i ntrodu cti on of E B C O i nto th e C + + p rog ram m i ng lang u ag e. N ath an M yers m ade i t p op u lar and p rop os ed a tem p late s i m i lar to ou r BaseMemberPair to tak e better adv antag e of i t. T h e B oos t li brary contai ns a cons i derably m ore s op h i s ti cated tem p late, called compressed_pair, th at res olv es s om e of th e p roblem s we rep orted for th e MyClass tem p late i n th i s ch ap ter. boost::compressed_pair can als o be u s ed i ns tead of ou r BaseMemberPair.

Page 353: CPlusPlus Templates The Complete Guide

Chapter 17. Metaprograms

M etapr og r ammi n g cons i s ts of " p rog ram m i ng a p rog ram ." I n oth er words , we lay ou t code th at th e p rog ram m i ng s ys tem ex ecu tes to g enerate new code th at i m p lem ents th e fu ncti onali ty we really want. U s u ally th e term metapr og r ammi n g i m p li es a reflex i v e attri bu te: T h e m etap rog ram m i ng com p onent i s p art of th e p rog ram for wh i ch i t g enerates a bi t of code/p rog ram .

W h y wou ld m etap rog ram m i ng be des i rable? A s wi th m os t oth er p rog ram m i ng tech ni q u es , th e g oal i s to ach i ev e m ore fu ncti onali ty wi th les s effort, wh ere effort can be m eas u red as code s i z e, m ai ntenance cos t, and s o forth . W h at ch aracteri z es m etap rog ram m i ng i s th at s om e u s er-defi ned com p u tati on h ap p ens at trans lati on ti m e. T h e u nderlyi ng m oti v ati on i s often p erform ance (th i ng s com p u ted at trans lati on ti m e can freq u ently be op ti m i z ed away) or i nterface s i m p li ci ty (a m etap rog ram i s g enerally s h orter th an wh at i t ex p ands to) or both .

M etap rog ram m i ng often reli es on th e concep ts of trai ts and typ e fu ncti ons as dev elop ed i n C h ap ter 15 . W e th erefore recom m end g etti ng fam i li ar wi th th at ch ap ter p ri or to delv i ng i nto th i s one.

Page 354: CPlusPlus Templates The Complete Guide

17.1 A First Example of a Metaprogram

I n 19 9 4 du ri ng a m eeti ng of th e C + + s tandardi z ati on com m i ttee, E rwi n U nru h di s cov ered th at tem p lates can be u s ed to com p u te s om eth i ng at com p i le ti m e. H e wrote a p rog ram th at p rodu ced p ri m e nu m bers . T h e i ntri g u i ng p art of th i s ex erci s e, h owev er, was th at th e p rodu cti on of th e p ri m e nu m bers was p erform ed by th e com p i ler du ri ng th e com p i lati on p roces s and not at ru n ti m e. Sp eci fi cally, th e com p i ler p rodu ced a s eq u ence of error m es s ag es wi th all p ri m e nu m bers from two u p to a certai n confi g u rable v alu e. A lth ou g h th i s p rog ram was n' t s tri ctly p ortable (error m es s ag es aren' t s tandardi z ed), th e p rog ram di d s h ow th at th e tem p late i ns tanti ati on m ech ani s m i s a p ri m i ti v e recu rs i v e lang u ag e th at can p erform nontri v i al com p u tati ons at com p i le ti m e. T h i s s ort of com p i le-ti m e com p u tati on th at occu rs th rou g h tem p late i ns tanti ati on i s com m only called template metapr og r ammi n g .

A s an i ntrodu cti on to th e detai ls of m etap rog ram m i ng we s tart wi th a s i m p le ex erci s e (we wi ll s h ow E rwi n' s p ri m e nu m ber p rog ram later on p ag e 3 18 ). T h e followi ng p rog ram s h ows h ow to com p u te at com p i le ti m e th e p ower of th ree for a g i v en v alu e:

// meta/pow3.hpp #ifndef POW3_HPP #define POW3_HPP // primary template to compute 3 to the Nth template<int N> class Pow3 { public: enum { result=3*Pow3<N-1>::result }; }; // full specialization to end the recursion template<> class Pow3<0> { public: enum { result = 1 }; }; #endif // POW3_HPP

T h e dri v i ng force beh i nd tem p late m etap rog ram m i ng i s recu rs i v e tem p late i ns tanti ati on. [1] I n ou r p rog ram to com p u te 3N , recu rs i v e tem p late i ns tanti ati on i s dri v en by th e followi ng two ru les :

[1] W e s aw an ex am p le of a recu rs i v e tem p late i n Secti on 12.4 on p ag e 200. I t cou ld be cons i dered a s i m p le cas e of

Page 355: CPlusPlus Templates The Complete Guide

m etap rog ram m i ng . 1. 3N = 3 * 3N -1 2 . 30 = 1

T h e fi rs t tem p late i m p lem ents th e g eneral recu rs i v e ru le:

template<int N> class Pow3 { public: enum { result = 3 * Pow3<N-1>::result }; };

W h en i ns tanti ated ov er a p os i ti v e i nteg er N , th e tem p late Pow3<> needs to com p u te th e v alu e for i ts enu m erati on v alu e result. T h i s v alu e i s s i m p ly twi ce th e corres p ondi ng v alu e i n th e s am e tem p late i ns tanti ated ov er N-1.

T h e s econd tem p late i s a s p eci ali z ati on th at ends th e recu rs i on. I t es tabli s h es th e result of Pow3<0>:

template<> class Pow3<0> { public: enum { result = 1 }; };

L et' s s tu dy th e detai ls of wh at h ap p ens wh en we u s e th i s tem p late to com p u te 37 by i ns tanti ati ng Pow3<7>:

// meta/pow3.cpp #include <iostream> #include "pow3.hpp" int main() { std::cout << "Pow3<7>::result = " << Pow3<7>::result << '\n'; }

F i rs t, th e com p i ler i ns tanti ates Pow3<7>. I ts result i s

3 * Pow3<6>::result

T h u s , th i s req u i res th e i ns tanti ati on of th e s am e tem p late for 6. Si m i larly, th e res u lt of Pow3<6> i ns tanti ates Pow3<5>, Pow3<4>, and s o forth . T h e recu rs i on s top s wh en Pow3<> i s i ns tanti ated ov er z ero wh i ch yi elds one as i ts result.

Page 356: CPlusPlus Templates The Complete Guide

T h e Pow3<> tem p late (i nclu di ng i ts s p eci ali z ati on) i s called a template metapr og r am. I t des cri bes a bi t of com p u tati on th at i s ev alu ated at trans lati on ti m e as p art of th e tem p late i ns tanti ati on p roces s . I t i s relati v ely s i m p le and m ay not look v ery u s efu l at fi rs t, bu t th ere are s i tu ati ons wh en s u ch a tool com es i n v ery h andy.

Page 357: CPlusPlus Templates The Complete Guide

17.2 Enumeration Values versus Static Constants

I n old C + + com p i lers , enu m erati on v alu es were th e only av ai lable p os s i bi li ty to h av e " tru e cons tants " (s o-called c on stan t-ex pr essi on s) i ns i de clas s declarati ons . H owev er, th i s h as ch ang ed du ri ng th e s tandardi z ati on of C + + , wh i ch i ntrodu ced th e concep t of i n-clas s s tati c cons tant i ni ti ali z ers . A bri ef ex am p le i llu s trates th e cons tru ct:

struct TrueConstants { enum { Three = 3 }; static int const Four = 4; };

I n th i s ex am p le, Four i s a " tru e cons tant" —j u s t as i s Three.

W i th th i s , ou r Pow3 m etap rog ram m ay als o look as follows :

// meta/pow3b.hpp #ifndef POW3_HPP #define POW3_HPP // primary template to compute 3 to the Nth template<int N> class Pow3 { public: static int const result = 3 * Pow3<N-1>::result; }; // full specialization to end the recursion template<> class Pow3<0> { public: static int const result = 1; }; #endif // POW3_HPP

T h e only di fference i s th e u s e of s tati c cons tant m em bers i ns tead of enu m erati on v alu es . H owev er, th ere i s a drawback wi th th i s v ers i on: Stati c cons tant m em bers are lv alu es . So, i f you h av e a declarati on s u ch as

void foo(int const&);

and you p as s i t th e res u lt of a m etap rog ram

Page 358: CPlusPlus Templates The Complete Guide

foo(Pow3<7>::result);

a com p i ler m u s t p as s th e addres s of Pow3<7>::result , wh i ch forces th e com p i ler to i ns tanti ate and allocate th e defi ni ti on for th e s tati c m em ber. A s a res u lt, th e com p u tati on i s no long er li m i ted to a p u re " com p i le-ti m e" effect.

E nu m erati on v alu es aren' t lv alu es (th at i s , th ey don' t h av e an addres s ). So, wh en you p as s th em " by reference, " no s tati c m em ory i s u s ed. I t' s alm os t ex actly as i f you p as s ed th e com p u ted v alu e as a li teral. T h es e cons i derati ons m oti v ate u s to u s e enu m erati on v alu es i n all m etap rog ram s th rou g h ou t th i s book .

Page 359: CPlusPlus Templates The Complete Guide

17.3 A Second Example: Computing the Square Root

L ets look at a s li g h tly m ore com p li cated ex am p le: a m etap rog ram th at com p u tes th e s q u are root of a g i v en v alu e N . T h e m etap rog ram look s as follows (ex p lanati on of th e tech ni q u e follows ):

// meta/sqrt1.hpp #ifndef SQRT_HPP #define SQRT_HPP // primary template to compute sqrt(N) template <int N, int LO=1, int HI=N> class Sqrt { public: // compute the midpoint, rounded up enum { mid = (LO+HI+1)/2 }; // search a not too large value in a halved interval enum { result = (N<mid*mid) ? Sqrt<N,LO,mid-1>::result : Sqrt<N,mid,HI>::result }; }; // partial specialization for the case when LO equals HI template<int N, int M> class Sqrt<N,M,M> { public: enum { result=M}; }; #endif // SQRT_HPP

T h e fi rs t tem p late i s th e g eneral recu rs i v e com p u tati on th at i s i nv ok ed wi th th e tem p late p aram eter N (th e v alu e for wh i ch to com p u te th e s q u are root) and two oth er op ti onal p aram eters . T h e latter rep res ent th e m i ni m u m and m ax i m u m v alu es th e res u lt can h av e. I f th e tem p late i s called wi th only one arg u m ent, we k now th at th e s q u are root i s at leas t one and at m os t th e v alu e i ts elf.

O u r recu rs i on th en p roceeds u s i ng a bi nary s earch tech ni q u e (often called method of b i sec ti on i n th i s contex t). I ns i de th e tem p late, we com p u te wh eth er result i s i n th e fi rs t or th e s econd h alf of th e rang e between LO and HI. T h i s cas e di fferenti ati on i s done u s i ng th e condi ti onal op erator ? :. I f mid2 i s g reater th an N, we conti nu e th e s earch i n th e fi rs t h alf. I f mid2 i s les s th an or eq u al to N, we u s e th e s am e tem p late for th e s econd h alf ag ai n.

T h e s p eci ali z ati on th at ends th e recu rs i v e p roces s i s i nv ok ed wh en LO and HI

Page 360: CPlusPlus Templates The Complete Guide

h av e th e s am e v alu e M, wh i ch i s ou r fi nal result.

A g ai n, let' s look at th e detai ls of a s i m p le p rog ram th at u s es th i s m etap rog ram :

// meta/sqrt1.cpp #include <iostream> #include "sqrt1.hpp" int main() { std::cout << "Sqrt<16>::result = " << Sqrt<16>::result << '\n'; std::cout << "Sqrt<25>::result = " << Sqrt<25>::result << '\n'; std::cout << "Sqrt<42>::result = " <<Sqrt<42>::result << '\n'; std::cout << "Sqrt<1>::result = " << Sqrt<1>::result << '\n'; }

T h e ex p res s i on

Sqrt<16>::result

i s ex p anded to

Sqrt<16,1,16>::result

I ns i de th e tem p late, th e m etap rog ram com p u tes Sqrt<16,1,16>::result as follows :

mid = (1+16+1)/2 = 9 result = (16<9*9) ? Sqrt<16,1,8>::result : Sqrt<16,9,16>::result = (16<81) ? Sqrt<16,1,8>::result : Sqrt<16,9,16>::result = Sqrt<16,1,8>::result

T h u s , th e res u lt i s com p u ted as Sqrt<16,1,8>::result , wh i ch i s ex p anded as follows :

mid = (1+8+1)/2 = 5 result = (16<5*5) ? Sqrt<16,1,4>::result : Sqrt<16,5,8>::result = (16<25) ? Sqrt<16,1,4>::result : Sqrt<16,5,8>::result = Sqrt<16,1,4>::result

Page 361: CPlusPlus Templates The Complete Guide

A nd s i m i larly Sqrt<16,1,4>::result i s decom p os ed as follows :

mid = (1+4+1)/2 = 3 result = (16<3*3) ? Sqrt<16,1,2>::result : Sqrt<16,3,4>::result = (16<9) ? Sqrt<16,1,2>::result : Sqrt<16,3,4>::result = Sqrt<16,3,4>::result

F i nally, Sqrt<16,3,4>::result res u lts i n th e followi ng :

mid = (3+4+1)/2 = 4 result = (16<4*4) ? Sqrt<16,3,3>::result : Sqrt<16,4,4>::result = (16<16) ? Sqrt<16,3,3>::result : Sqrt<16,4,4>::result = Sqrt<16,4,4>::result

and Sqrt<16,4,4>::result ends th e recu rs i v e p roces s becau s e i t m atch es th e ex p li ci t s p eci ali z ati on th at catch es eq u al h i g h and low bou nds . T h e fi nal res u lt i s th erefore as follows :

result = 4

Tracking All Instantiations

I n th e p recedi ng ex am p le, we followed th e s i g ni fi cant i ns tanti ati ons th at com p u te th e s q u are root of 16. H owev er, wh en a com p i ler ev alu ates th e ex p res s i on

(16<=8*8) ? Sqrt<16,1,8>::result : Sqrt<16,9,16>::result

i t not only i ns tanti ates th e tem p lates i n th e p os i ti v e branch , bu t als o th os e i n th e neg ati v e branch (Sqrt<16,9,16>). F u rth erm ore, becau s e th e code attem p ts to acces s a m em ber of th e res u lti ng clas s typ e u s i ng th e :: op erator, all th e m em bers i ns i de th at clas s typ e are als o i ns tanti ated. T h i s m eans th at th e fu ll i ns tanti ati on of Sqrt<16,9,16> res u lts i n th e fu ll i ns tanti ati on of Sqrt<16,9,12> and Sqrt<16,13,16>. W h en th e wh ole p roces s i s ex am i ned i n detai l, we fi nd th at doz ens of i ns tanti ati ons end u p bei ng g enerated. T h e total nu m ber i s alm os t twi ce th e v alu e of N.

T h i s i s u nfortu nate becau s e tem p late i ns tanti ati on i s a fai rly ex p ens i v e p roces s for m os t com p i lers , p arti cu larly wi th res p ect to m em ory cons u m p ti on. F ortu nately,

Page 362: CPlusPlus Templates The Complete Guide

th ere are tech ni q u es to redu ce th i s ex p los i on i n th e nu m ber of i ns tanti ati ons . W e u s e s p eci ali z ati ons to s elect th e res u lt of com p u tati on i ns tead of u s i ng th e condi ti on op erator ?:. T o i llu s trate th i s , we rewri te ou r Sqrt m etap rog ram as follows :

// meta/sqrt2.hpp #include "ifthenelse.hpp" // primary template for main recursive step template<int N, int LO=1, int HI=N> class Sqrt { public: // compute the midpoint, rounded up enum { mid = (LO+HI+1)/2 }; // search a not too large value in a halved interval typedef typename IfThenElse<(N<mid*mid), Sqrt<N,LO,mid-1>, Sqrt<N,mid,HI> >::ResultT SubT; enum { result = SubT::result }; }; // partial specialization for end of recursion criterion template<int N, int S> class Sqrt<N, S, S> { public: enum { result = S }; };

T h e k ey ch ang e h ere i s th e u s e of th e IfThenElse tem p late, wh i ch was i ntrodu ced i n Secti on 15 .2.4 on p ag e 27 2:

// meta/ifthenelse.hpp #ifndef IFTHENELSE_HPP #define IFTHENELSE_HPP // primary template: yield second or third argument depending on first argument template<bool C, typename Ta, typename Tb> class IfThenElse; // partial specialization: true yields second argument template<typename Ta, typename Tb> class IfThenElse<true, Ta, Tb> { public: typedef Ta ResultT; }; // partial specialization: false yields third argument template<typename Ta, typename Tb> class IfThenElse<false, Ta, Tb> { public: typedef Tb ResultT;

Page 363: CPlusPlus Templates The Complete Guide

}; #endif // IFTHENELSE_HPP

R em em ber, th e IfThenElse tem p late i s a dev i ce th at s elects between two typ es bas ed on a g i v en B oolean cons tant. I f th e cons tant i s tru e, th e fi rs t typ e i s typedefed to ResultT ; oth erwi s e, ResultT s tands for th e s econd typ e. A t th i s p oi nt i t i s i m p ortant to rem em ber th at defi ni ng a typ edef for a clas s tem p late i ns tance does not cau s e a C + + com p i ler to i ns tanti ate th e body of th at i ns tance. T h erefore, wh en we wri te

typedef typename IfThenElse<(N<mid*mid), Sqrt<N,LO,mid-1>, Sqrt<N,mid,HI> >::ResultT SubT;

nei th er Sqrt<N,LO,mid-1> nor Sqrt<N,mid,HI> i s fu lly i ns tanti ated. W h i ch ev er of th es e two typ es ends u p bei ng a s ynonym for SubT i s fu lly i ns tanti ated wh en look i ng u p SubT::result. I n contras t to ou r fi rs t ap p roach , th i s s trateg y leads to a nu m ber of i ns tanti ati ons th at i s p rop orti onal to log 2(N): a v e ry si g ni f i cant re du cti o n i n th e co st o f m e tapro g ram m i ng w h e n N g e ts m o de rate l y l arg e .

Page 364: CPlusPlus Templates The Complete Guide

17.4 Using Induction Variables

Y o u m ay arg u e th at th e w ay th e m e tapro g ram i s w ri tte n i n th e pre v i o u s e x am pl e l o o k s rath e r co m pl i cate d. A nd y o u m ay w o nde r w h e th e r y o u h av e l e arne d so m e th i ng you can u se w h e ne v e r y o u h av e a pro bl e m to so l v e by a m e tapro g ram . S o , l e t' s l o o k f o r a m o re " nai v e " and m ay be " m o re i te rati v e " i m pl e m e ntati o n o f a m e tapro g ram th at co m pu te s th e sq u are ro o t.

A " nai v e i te rati v e al g o ri th m " can be f o rm u l ate d as f o l l o w s: T o co m pu te th e sq u are ro o t o f a g i v e n v al u e N, w e w ri te a l o o p i n w h i ch a v ari abl e I i te rate s f ro m o ne to N u nti l i ts sq u are i s e q u al to o r g re ate r th an N. T h i s v al u e I i s o u r sq u are ro o t o f N. If w e f o rm u l ate th i s pro bl e m i n o rdi nary C + + , i t l o o k s as f o l l o w s:

int I; for (I=1; I*I<N; ++I) { ; } // I now contains the square root of N

H o w e v e r, as a m e tapro g ram w e h av e to f o rm u l ate th i s l o o p i n a re cu rsi v e w ay , and w e ne e d an e nd cri te ri o n to e nd th e re cu rsi o n. A s a re su l t, an i m pl e m e ntati o n o f th i s l o o p as a m e tapro g ram l o o k s as f o l l o w s:

// meta/sqrt3.hpp #ifndef SQRT_HPP #define SQRT_HPP // primary template to compute sqrt(N) via iteration template <int N, int I=1> class Sqrt { public: enum { result = (I*I<N) ? Sqrt<N,I+1>::result : I }; }; // partial specialization to end the iteration template<int N> class Sqrt<N,N> { public: enum { result = N }; }; #endif // SQRT_HPP

W e l o o p by " i te rati ng " I o v e r Sqrt<N,I>. A s l o ng as I*I<N y i e l ds true, w e u se th e re su l t o f th e ne x t i te rati o n Sqrt<N,I+1>::result as re su l t. O th e rw i se I i s

Page 365: CPlusPlus Templates The Complete Guide

o u r re su l t.

F o r e x am pl e , i f w e e v al u ate Sqrt<16> th i s g e ts e x pande d to Sqrt<16,1>. T h u s, w e start an i te rati o n w i th o ne as a v al u e o f th e so -cal l e d i nduc t i on v a r i a b l e I. No w , as l o ng as I2 (th at i s I*I) i s l e ss th an N, w e u se th e ne x t i te rati o n v al u e by co m pu ti ng Sqrt<N,I+1>::result. W h e n I2 i s e q u al to o r g re ate r th an N w e k no w th at I i s th e result.

Y o u m ay w o nde r w h y w e ne e d a te m pl ate spe ci al i z ati o n to e nd th e re cu rsi o n be cau se th e f i rst te m pl ate al w ay s, so o ne r o r l ate r, f i nds I as th e re su l t, w h i ch se e m s to e nd th e re cu rsi o n. A g ai n, th i s i s th e e f f e ct o f th e i nstanti ati o n o f bo th branch e s o f o pe rato r ?: , w h i ch w as di scu sse d i n th e pre v i o u s se cti o n. T h u s, th e co m pi l e r co m pu te s th e re su l t o f Sqrt<4> by i nstanti ati ng as f o l l o w s:

• S te p 1 : •

• result = (1*1<4) ? Sqrt<4,2>::result : 1

• S te p 2 : •

• result = (1*1<4) ? (2*2<4) ? Sqrt<4,3>::result • : 2

: 1

• S te p 3 : •

• result = (1*1<4) ? (2*2<4) ? (3*3<4) ? Sqrt<4,4>::result

• : 3 • : 2

: 1

• S te p 4 : • • result = (1*1<4) ? (2*2<4) ? (3*3<4) ? 4

• : 3 • : 2

: 1

A l th o u g h w e f i nd th e re su l t i n ste p 2 , th e co m pi l e r i nstanti ate s u nti l w e f i nd a ste p th at e nds th e re cu rsi o n w i th a spe ci al i z ati o n. W i th o u t th e spe ci al i z ati o n, th e co m pi l e r w o u l d co nti nu e to i nstanti ate u nti l i nte rnal co m pi l e r l i m i ts are re ach e d.

A g ai n, th e appl i cati o n o f th e IfThenElse te m pl ate so l v e s th e pro bl e m :

// meta/sqrt4.hpp

Page 366: CPlusPlus Templates The Complete Guide

#ifndef SQRT_HPP #define SQRT_HPP #include "ifthenelse.hpp" // template to yield template argument as result template<int N> class Value { public: enum { result = N }; }; // template to compute sqrt(N) via iteration template <int N, int I=1> class Sqrt { public: // instantiate next step or result type as branch typedef typename IfThenElse<(I*I<N), Sqrt<N,I+1>, Value<I> >::ResultT SubT; // use the result of branch type enum { result = SubT::result }; }; #endif // SQRT_HPP

Inste ad o f th e e nd cri te ri o n w e u se a Value<> te m pl ate th at re tu rns th e v al u e o f th e te m pl ate arg u m e nt as result.

A g ai n, u si ng IfThenElse<> l e ads to a nu m be r o f i nstanti ati o ns th at i s pro po rti o nal to log 2(N) i nste ad o f N. T h i s i s a v e ry si g ni f i cant re du cti o n i n th e co st o f m e tapro g ram m i ng . A nd f o r co m pi l e rs w i th te m pl ate i nstanti ati o n l i m i ts, th i s m e ans th at y o u can e v al u ate th e sq u are ro o t o f m u ch l arg e r v al u e s. If y o u r co m pi l e r su ppo rts u p to 6 4 ne ste d i nstanti ati o ns, f o r e x am pl e , y o u can pro ce ss th e sq u are ro o t o f u p to 4 0 9 6 (i nste ad o f u p to 6 4 ).

T h e o u tpu t o f th e " i te rati v e " Sqrt te m pl ate s i s as f o l l o w s:

Sqrt<16>::result = 4 Sqrt<25>::result = 5 Sqrt<42>::result = 7 Sqrt<1>::result = 1

No te th at th i s i m pl e m e ntati o n pro du ce s th e i nte g e r sq u are ro o t ro u nde d u p f o r si m pl i ci ty (th e sq u are ro o t o f 4 2 i s pro du ce d as 7 i nste ad o f 6 ).

Page 367: CPlusPlus Templates The Complete Guide

17.5 Computational Completeness

T h e Pow3<> and Sqrt<> e x am pl e s sh o w th at a te m pl ate m e tapro g ram can co ntai n:

• S tate v ari abl e s: th e te m pl ate param e te rs • L o o p co nstru cts: th ro u g h re cu rsi o n • P ath se l e cti o n: by u si ng co ndi ti o nal e x pre ssi o ns o r spe ci al i z ati o ns • Inte g e r ari th m e ti c

If th e re are no l i m i ts to th e am o u nt o f re cu rsi v e i nstanti ati o ns and th e am o u nt o f state v ari abl e s th at are al l o w e d, i t can be sh o w n th at th i s i s su f f i ci e nt to co m pu te any th i ng th at i s co m pu tabl e . H o w e v e r, i t m ay no t be co nv e ni e nt to do so u si ng te m pl ate s. F u rth e rm o re , te m pl ate i nstanti ati o n ty pi cal l y re q u i re s su bstanti al co m pi l e r re so u rce s, and e x te nsi v e re cu rsi v e i nstanti ati o n q u i ck l y sl o w s do w n a co m pi l e r o r e v e n e x h au sts th e re so u rce s av ai l abl e . T h e C + + standard re co m m e nds bu t do e s no t m andate th at 1 7 l e v e l s o f re cu rsi v e i nstanti ati o ns be al l o w e d as a m i ni m u m . Inte nsi v e te m pl ate m e tapro g ram m i ng e asi l y e x h au sts su ch a l i m i t.

H e nce , i n practi ce , te m pl ate m e tapro g ram s sh o u l d be u se d spari ng l y . T h e are a f e w si tu ati o ns, h o w e v e r, w h e n th e y are i rre pl ace abl e as a to o l to i m pl e m e nt co nv e ni e nt te m pl ate s. In parti cu l ar, th e y can so m e ti m e s be h i dde n i n th e i nnards o f m o re co nv e nti o nal te m pl ate s to sq u e e z e m o re pe rf o rm ance o u t o f cri ti cal al g o ri th m i m pl e m e ntati o ns.

Page 368: CPlusPlus Templates The Complete Guide

17.6 Recursive Instantiation versus Recursive Template Arguments

C o nsi de r th e f o l l o w i ng re cu rsi v e te m pl ate :

template<typename T, typename U> struct Doublify {}; template<int N> struct Trouble { typedef Doublify<typename Trouble<N-1>::LongType, typename Trouble<N-1>::LongType> LongType; }; template<> struct Trouble<0> { typedef double LongType; }; Trouble<10>::LongType ouch;

T h e u se o f Trouble<10>::LongType no t o nl y tri g g e rs th e re cu rsi v e i nstanti ati o n o f Trouble<9> , Trouble<8> , … , Trouble<0>, bu t i t al so i nstanti ate s Doublify o v e r i ncre asi ng l y co m pl e x ty pe s. Inde e d, T abl e 1 7 .1 i l l u strate s h o w q u i ck l y i t g ro w s.

A s can be se e n f ro m T abl e 1 7 .1 , th e co m pl e x i ty o f th e ty pe de scri pti o n o f th e e x pre ssi o n Trouble<N>::LongType g ro w s e x po ne nti al l y w i th N. In g e ne ral , su ch a si tu ati o n stre sse s a C + + co m pi l e r e v e n m o re th an re cu rsi v e i nstanti ati o ns th at do no t i nv o l v e re cu rsi v e te m pl ate arg u m e nts. O ne o f th e pro bl e m s h e re i s th at a co m pi l e r k e e ps a re pre se ntati o n o f th e m ang l e d nam e f o r th e ty pe . T h i s m ang l e d nam e e nco de s th e e x act te m pl ate spe ci al i z ati o n i n so m e w ay , and e arl y C + + i m pl e m e ntati o ns u se d an e nco di ng th at i s ro u g h l y pro po rti o nal to th e l e ng th o f th e te m pl ate -i d. T h e se co m pi l e rs th e n u se d w e l l o v e r 1 0 , 0 0 0 ch aracte rs f o r Trouble<10>::LongType.

Ne w e r C + + i m pl e m e ntati o ns tak e i nto acco u nt th e f act th at ne ste d te m pl ate -i ds are f ai rl y co m m o n i n m o de rn C + + pro g ram s and u se cl e v e r co m pre ssi o n te ch ni q u e s to re du ce co nsi de rabl y th e g ro w th

Table 17.1. Growth of Trouble<N>::LongType Ty p ed ef N am e U n d erly i n g Ty p e

Trouble<0>::LongType Trouble<1>::LongType Trouble<2>::LongType Trouble<3>::LongType

double Doublify<double,double> Doublify<Doublify<double,double>, Doublify<double,double> > Doublify<Doublify<Doublify<double,double>,

Page 369: CPlusPlus Templates The Complete Guide

Trouble<3>::LongType Doublify<Doublify<Doublify<double,double>, Doublify<double,double> >, <Doublify<double,double>, Doublify<double,double> > >

i n nam e e nco di ng (f o r e x am pl e , a f e w h u ndre d ch aracte rs f o r Trouble<10>::LongType). S ti l l , al l o th e r th i ng s be i ng e q u al , i t i s pro babl y pre f e rabl e to o rg ani z e re cu rsi v e i nstanti ati o n i n su ch a w ay th at te m pl ate arg u m e nts ne e d no t al so be ne ste d re cu rsi v e l y .

Page 370: CPlusPlus Templates The Complete Guide

17.7 Using Metaprograms to Unroll Loops

O ne o f th e f i rst practi cal appl i cati o ns o f m e tapro g ram m i ng w as th e u nro l l i ng o f l o o ps f o r nu m e ri c co m pu tati o ns, w h i ch i s sh o w n h e re as a co m pl e te e x am pl e .

Nu m e ri c appl i cati o ns o f te n h av e to pro ce ss n-di m e nsi o nal array s o r m ath e m ati cal v e cto rs. O ne ty pi cal o pe rati o n i s th e co m pu tati o n o f th e so -cal l e d dot p r oduc t . T h e do t pro du ct o f tw o m ath e m ati cal v e cto rs a and b i s th e su m o f al l pro du cts o f co rre spo ndi ng e l e m e nts i n bo th v e cto rs. F o r e x am pl e , i f e ach v e cto rs h as th re e e l e m e nts, th e re su l t i s

a[0]*b[0] + a[1]*b[1] + a[2]*b[2]

A m ath e m ati cal l i brary ty pi cal l y pro v i de s a f u ncti o n to co m pu te su ch a do t pro du ct. C o nsi de r th e f o l l o w i ng strai g h tf o rw ard i m pl e m e ntati o n:

// meta/loop1.hpp #ifndef LOOP1_HPP #define LOOP1_HPP template <typename T> inline T dot_product (int dim, T* a, T* b) { T result = 0; for (int i=0; i<dim; ++i) { result += a[i]*b[i]; } return result; } #endif // LOOP1_HPP

W h e n w e cal l th i s f u ncti o n as f o l l o w s

// meta/loop1.cpp #include <iostream> #include "loop1.hpp" int main() { int a[3] = { 1, 2, 3 }; int b[3] = { 5, 6, 7 }; std::cout << "dot_product(3,a,b) = " << dot_product(3,a,b) << '\n'; std::cout << "dot_product(3,a,a) = " << dot_product(3,a,a)

Page 371: CPlusPlus Templates The Complete Guide

<< '\n'; }

w e g e t th e f o l l o w i ng re su l t:

dot_product(3,a,b) = 38 dot_product(3,a,a) = 14

T h i s i s co rre ct, bu t i t tak e s to o l o ng f o r se ri o u s h i g h -pe rf o rm ance appl i cati o ns. E v e n de cl ari ng th e f u ncti o n i nl i ne i s o f te n no t su f f i ci e nt to attai n o pti m al pe rf o rm ance .

T h e pro bl e m i s th at co m pi l e rs u su al l y o pti m i z e l o o ps f o r m any i te rati o ns, w h i ch i s co u nte rpro du cti v e i n th i s case . S i m pl y e x pandi ng th e l o o p to

a[0]*b[0] + a[1]*b[1] + a[2]*b[2]

w o u l d be a l o t be tte r.

O f co u rse , th i s pe rf o rm ance do e sn' t m atte r i f w e co m pu te o nl y so m e do t pro du cts f ro m ti m e to ti m e . B u t, i f w e u se th i s l i brary co m po ne nt to pe rf o rm m i l l i o ns o f do t pro du ct co m pu tati o ns, th e di f f e re nce s be co m e si g ni f i cant.

O f co u rse , w e co u l d w ri te th e co m pu tati o n di re ctl y i nste ad o f cal l i ng dot_product() , o r w e co u l d pro v i de spe ci al f u ncti o ns f o r do t pro du ct co m pu tati o ns w i th o nl y a f e w di m e nsi o ns, bu t th i s i s te di o u s. T e m pl ate m e tapro g ram m i ng so l v e s th i s i ssu e f o r u s: W e " pro g ram " to u nro l l th e l o o ps. H e re i s th e m e tapro g ram :

// meta/loop2.hpp #ifndef LOOP2_HPP #define LOOP2_HPP // primary template template <int DIM, typename T> class DotProduct { public: static T result (T* a, T* b) { return *a * *b + DotProduct<DIM-1,T>::result(a+1,b+1); } }; // partial specialization as end criteria template <typename T> class DotProduct<1,T> { public: static T result (T* a, T* b) { return *a * *b; }

Page 372: CPlusPlus Templates The Complete Guide

}; // convenience function template <int DIM, typename T> inline T dot_product (T* a, T* b) { return DotProduct<DIM,T>::result(a,b); } #endif // LOOP2_HPP

No w , by ch ang i ng y o u r appl i cati o n pro g ram o nl y sl i g h tl y , y o u can g e t th e sam e re su l t:

// meta/loop2.cpp #include <iostream> #include "loop2.hpp" int main() { int a[3] = { 1, 2, 3}; int b[3] = { 5, 6, 7}; std::cout << "dot_product<3>(a,b) = " << dot_product<3>(a,b) << '\n'; std::cout << "dot_product<3>(a,a) = " << dot_product<3>(a,a) << '\n'; }

Inste ad o f w ri ti ng

dot_product(3,a,b)

w e w ri te

dot_product<3>(a,b)

T h i s e x pre ssi o n i nstanti ate s a co nv e ni e nce f u ncti o n te m pl ate th at transl ate s th e cal l i nto

DotProduct<3,int>::result(a,b)

A nd th i s i s th e start o f th e m e tapro g ram .

Insi de th e m e tapro g ram th e result i s th e pro du ct o f th e f i rst e l e m e nts o f a and b pl u s th e result o f th e do t pro du ct o f th e re m ai ni ng di m e nsi o ns o f th e v e cto rs starti ng w i th th e i r ne x t e l e m e nts:

Page 373: CPlusPlus Templates The Complete Guide

template <int DIM, typename T> class DotProduct { public: static T result (T* a, T* b) { return *a * *b + DotProduct<DIM-1,T>::result(a+1,b+1); } };

T h e e nd cri te ri o n i s th e case o f a o ne -di m e nsi o nal v e cto r:

template <typename T> class DotProduct<1,T> { public: static T result (T* a, T* b) { return *a * *b; } };

T h u s, f o r

dot_product<3>(a,b)

th e i nstanti ati o n pro ce ss co m pu te s th e f o l l o w i ng :

DotProduct<3,int>::result(a,b) = *a * *b + DotProduct<2,int>::result(a+1,b+1) = *a * *b + *(a+1) * *(b+1) + DotProduct<1,int>::result(a+2,b+2) = *a * *b + *(a+1) * *(b+1) + *(a+2) * *(b+2)

No te th at th i s w ay o f pro g ram m i ng re q u i re s th at th e nu m be r o f di m e nsi o ns i s k no w n at co m pi l e ti m e , w h i ch i s o f te n (bu t no t al w ay s) th e case .

L i brari e s, su ch as B l i tz + + (se e [B l i tz + + ]), th e M T L l i brary (se e [M T L ]), and P O O M A (se e [P O O M A ]), u se th e se k i nds o f m e tapro g ram s to pro v i de f ast ro u ti ne s f o r nu m e ri c l i ne ar al g e bra. S u ch m e tapro g ram s o f te n do a be tte r j o b th an o pti m i z e rs be cau se th e y can i nte g rate h i g h e r-l e v e l k no w l e dg e i nto th e co m pu tati o ns. [ 2] T h e i ndu stri al -stre ng th i m pl e m e ntati o n o f su ch l i brari e s i nv o l v e s m any m o re de tai l s th an th e te m pl ate -re l ate d i ssu e s w e pre se nt h e re . Inde e d, re ck l e ss u nro l l i ng do e s no t al w ay s l e ad to o pti m al ru nni ng ti m e s. H o w e v e r, th e se addi ti o nal e ng i ne e ri ng co nsi de rati o ns f al l o u tsi de th e sco pe o f o u r te x t.

[ 2] In so m e si tu ati o ns m e tapro g ram s si g ni f i cantl y o u tpe rf o rm th e i r F o rtran co u nte rparts, e v e n th o u g h F o rtran o pti m i z e rs are u su al l y h i g h l y tu ne d f o r th e se so rts o f appl i cati o ns.

Page 374: CPlusPlus Templates The Complete Guide

17.8 Afternotes

A s m e nti o ne d e arl i e r, th e e arl i e st do cu m e nte d e x am pl e o f a m e tapro g ram w as by E rw i n U nru h , th e n re pre se nti ng S i e m e ns o n th e C + + standardi z ati o n co m m i tte e . H e no te d th e co m pu tati o nal co m pl e te ne ss o f th e te m pl ate i nstanti ati o n pro ce ss and de m o nstrate d h i s po i nt by de v e l o pi ng th e f i rst m e tapro g ram . H e u se d th e M e taw are co m pi l e r and co ax e d i t i nto i ssu i ng e rro r m e ssag e s th at w o u l d co ntai n su cce ssi v e pri m e nu m be rs. H e re i s th e co de th at w as ci rcu l ate d at a C + + co m m i tte e m e e ti ng i n 1 9 9 4 (m o di f i e d so th at i t no w co m pi l e s o n standard co nf o rm i ng co m pi l e rs) [ 3 ] :

[ 3 ] T h ank s to E rw i n U nru h f o r pro v i di ng th e co de f o r th i s bo o k . Y o u can f i nd th e o ri g i nal e x am pl e at [U nru h P ri m e O ri g ].

// meta/unruh.cpp // prime number computation by Erwin Unruh template <int p, int i> class is_prime { public: enum { prim = (p==2) || (p%i) && is_prime<(i>2?p:0),i-1>::prim }; }; template<> class is_prime<0,0> { public: enum {prim=1}; }; template<> class is_prime<0,1> { public: enum {prim=1}; }; template <int i> class D { public: D(void*); }; template <int i> class Prime_print { // primary template for loop to print prime numbers public: Prime_print<i-1> a; enum { prim = is_prime<i,i-1>::prim }; void f() { D<i> d = prim ? 1 : 0;

Page 375: CPlusPlus Templates The Complete Guide

a.f(); } }; template<> class Prime_print<1> { // full specialization to end the loop public: enum {prim=0}; void f() { D<1> d = prim ? 1 : 0; }; }; #ifndef LAST #define LAST 18 #endif int main() { Prime_print<LAST> a; a.f(); }

If y o u co m pi l e th i s pro g ram , th e co m pi l e r w i l l pri nt e rro r m e ssag e s w h e n i n Prime_print::f() th e i ni ti al i z ati o n o f d f ai l s. T h i s h appe ns w h e n th e i ni ti al v al u e i s 1 be cau se th e re i s o nl y a co nstru cto r f o r void*, and o nl y 0 h as a v al i d co nv e rsi o n to void*. F o r e x am pl e , o n o ne co m pi l e r w e g e t (am o ng o th e r m e ssag e s) th e f o l l o w i ng e rro rs:

unruh.cpp:36: conversion from 'int' to non-scalar type 'D<17>' requested unruh.cpp:36: conversion from 'int' to non-scalar type 'D<13>' requested unruh.cpp:36: conversion from 'int' to non-scalar type 'D<11>' requested unruh.cpp:36: conversion from 'int' to non-scalar type 'D<7>' requested unruh.cpp:36: conversion from 'int' to non-scalar type 'D<5>' requested unruh.cpp:36: conversion from 'int' to non-scalar type 'D<3>' requested unruh.cpp:36: conversion from 'int' to non-scalar type 'D<2>' requested

T h e co nce pt o f C + + te m pl ate m e tapro g ram m i ng as a se ri o u s pro g ram m i ng to o l w as f i rst m ade po pu l ar (and so m e w h at f o rm al i z e d) by T o dd V e l dh u i z e n i n h i s pape r U s i ng C + + T e m p l a t e M e t a p r og r a m s (se e [V e l dh u i z e nM e ta9 5 ]). T o dd' s w o rk o n B l i tz + + (a nu m e ri c array l i brary f o r C + + , se e [B l i tz + + ]) al so i ntro du ce d m any re f i ne m e nts and e x te nsi o ns to th e m e tapro g ram m i ng (and to e x pre ssi o n te m pl ate te ch ni q u e s, i ntro du ce d i n th e ne x t ch apte r).

Page 376: CPlusPlus Templates The Complete Guide

Chapter 18. Expression Templates

In th i s ch apte r w e e x pl o re a te m pl ate pro g ram m i ng te ch ni q u e cal l e d e x p r e s s i on t e m p l a t e s . It w as o ri g i nal l y i nv e nte d i n su ppo rt o f nu m e ri c array cl asse s, and th at i s al so th e co nte x t i n w h i ch w e i ntro du ce i t h e re .

A nu m e ri c array cl ass su ppo rts nu m e ri c o pe rati o ns o n w h o l e array o bj e cts. F o r e x am pl e , i t i s po ssi bl e to add tw o array s, and th e re su l t co ntai ns e l e m e nts th at are th e su m s o f th e co rre spo ndi ng v al u e s i n th e arg u m e nt array s. S i m i l arl y , a w h o l e array can be m u l ti pl i e d by a scal ar, m e ani ng th at e ach e l e m e nt o f th e array i s scal e d. Natu ral l y , i t i s de si rabl e to k e e p th e o pe rato r no tati o n th at i s so f am i l i ar f o r bu i l t-i n scal ar ty pe s:

Array<double> x(1000), y(1000); … x = 1.2*x + x*y;

F o r th e se ri o u s nu m be r cru nch e r i t i s cru ci al th at su ch e x pre ssi o ns be e v al u ate d as e f f i ci e ntl y as can be e x pe cte d f ro m th e pl atf o rm o n w h i ch th e co de i s ru n. A ch i e v i ng th i s w i th th e co m pact o pe rato r no tati o n o f th i s e x am pl e i s no tri v i al task , bu t e x pre ssi o n te m pl ate s w i l l co m e to o u r re scu e .

E x pre ssi o n te m pl ate s are re m i ni sce nt o f te m pl ate m e tapro g ram m i ng . In part th i s i s du e to th e f act th at e x pre ssi o n te m pl ate s re l y o n so m e ti m e s de e pl y ne ste d te m pl ate i nstanti ati o ns, w h i ch are no t u nl i k e th e re cu rsi v e i nstanti ati o ns e nco u nte re d i n te m pl ate m e tapro g ram s. T h e f act th at bo th te ch ni q u e s w e re o ri g i nal l y de v e l o pe d to su ppo rt h i g h -pe rf o rm ance (se e o u r e x am pl e u si ng te m pl ate s to u nro l l l o o ps o n pag e 3 1 4 ) array o pe rati o ns pro babl y al so co ntri bu te s to a se nse th at th e y are re l ate d. C e rtai nl y th e te ch ni q u e s are co m pl e m e ntary . F o r e x am pl e , m e tapro g ram m i ng i s co nv e ni e nt f o r sm al l , f i x e d-si z e array w h e re as e x pre ssi o n te m pl ate s are v e ry e f f e cti v e f o r o pe rati o ns o n m e di u m -to -l arg e array s si z e d at ru n ti m e .

Page 377: CPlusPlus Templates The Complete Guide

18.1 Temporaries and Split Loops

T o m o ti v ate e x pre ssi o n te m pl ate s, l e t' s start w i th a strai g h tf o rw ard (o r m ay be " nai v e " ) appro ach to i m pl e m e nt te m pl ate s th at e nabl e nu m e ri c array o pe rati o ns. A basi c array te m pl ate m i g h t l o o k as f o l l o w s (SArray stands f o r s i m p l e a r r a y):

// exprtmpl/sarray1.hpp #include <stddef.h> #include <cassert> template<typename T> class SArray { public: // create array with initial size explicit SArray (size_t s) : storage(new T[s]), storage_size(s) { init(); } // copy constructor SArray (SArray<T> const& orig) : storage(new T[orig.size()]), storage_size(orig.size()) { copy(orig); } // destructor: free memory ~SArray() { delete[] storage; } // assignment operator SArray<T>& operator= (SArray<T> const& orig) { if (&orig!=this) { copy(orig); } return *this; } // return size size_t size() const { return storage_size; } // index operator for constants and variables T operator[] (size_t idx) const { return storage[idx]; } T& operator[] (size_t idx) { return storage[idx]; } protected: // init values with default constructor

Page 378: CPlusPlus Templates The Complete Guide

void init() { for (size_t idx = 0; idx<size(); ++idx) { storage[idx] = T(); } } // copy values of another array void copy (SArray<T> const& orig) { assert(size()==orig.size()); for (size_t idx = 0; idx<size(); ++idx) { storage[idx] = orig.storage[idx]; } } private: T* storage; // storage of the elements size_t storage_size; // number of elements };

T h e nu m e ri c o pe rato rs can be co de d as f o l l o w s:

// exprtmpl/sarrayops1.hpp // addition of two SArrays template<typename T> SArray<T> operator+ (SArray<T> const& a, SArray<T> const& b) { SArray<T> result(a.size()); for (size_t k = 0; k<a.size(); ++k) { result[k] = a[k]+b[k]; } return result; } // multiplication of two SArrays template<typename T> SArray<T> operator* (SArray<T> const& a, SArray<T> const& b) { SArray<T> result(a.size()); for (size_t k = 0; k<a.size(); ++k) { result[k] = a[k]*b[k]; } return result; } // multiplication of scalar and SArray template<typename T> SArray<T> operator* (T const& s, SArray<T> const& a) { SArray<T> result(a.size()); for (size_t k = 0; k<a.size(); ++k) { result[k] = s*a[k]; } return result; } // multiplication of SArray and scalar // addition of scalar and SArray // addition of SArray and scalar …

Page 379: CPlusPlus Templates The Complete Guide

M any o th e r v e rsi o ns o f th e se and o th e r o pe rato rs can be w ri tte n, bu t th e se su f f i ce to al l o w o u r e x am pl e e x pre ssi o n:

// exprtmpl/sarray1.cpp #include "sarray1.hpp" #include "sarrayops1.hpp" int main() { SArray<double> x(1000), y(1000); … x = 1.2*x + x*y; }

T h i s i m pl e m e ntati o n tu rns o u t to be v e ry i ne f f i ci e nt f o r tw o re aso ns:

1. E v e r y a p p l i c a t i o n o f a n o p e r a t o r ( e x c e p t a s s i g n m e n t ) c r e a t e s a t l e a s t o n e t e m p o r a r y a r r a y ( t h a t i s , a t l e a s t t h r e e t e m p o r a r y a r r a y s o f s i z e 1, 0 0 0 e a c h i n o u r e x a m p l e , a s s u m i n g a c o m p i l e r p e r f o r m s a l l t h e a l l o w a b l e t e m p o r a r y c o p y e l i m i n a t i o n s ) .

2 . E v e r y a p p l i c a t i o n o f a n o p e r a t o r r e q u i r e s a d d i t i o n a l t r a v e r s a l s o f t h e a r g u m e n t a n d r e s u l t a r r a y s ( a p p r o x i m a t e l y 6 , 0 0 0 double s a r e r e a d , a n d a p p r o x i m a t e l y 4 , 0 0 0 doubles a r e w r i t t e n i n o u r e x a m p l e , a s s u m i n g o n l y t h r e e t e m p o r a r y SArray o b j e c t s a r e g e n e r a t e d ) .

W h at h appe ns co ncre te l y i s a se q u e nce o f l o o ps th at o pe rate s w i th te m po rari e s:

tmp1 = 1.2*x; // loop of 1,000 operations // plus creation and destruction of tmp1 tmp2 = x*y // loop of 1,000 operations // plus creation and destruction of tmp2 tmp3 = tmp1+tmp2; // loop of 1,000 operations // plus creation and destruction of tmp3 x = tmp3; // 1,000 read operations and 1,000 write operations

T h e cre ati o n o f u nne e de d te m po rari e s o f te n do m i nate s th e ti m e ne e de d f o r o pe rati o ns o n sm al l array s u nl e ss spe ci al f ast al l o cato rs are u se d. F o r tru l y l arg e array s, te m po rari e s are to tal l y u nacce ptabl e be cau se th e re i s no sto rag e to h o l d th e m . (C h al l e ng i ng nu m e ri c si m u l ati o ns o f te n try to u se al l th e av ai l abl e m e m o ry f o r m o re re al i sti c re su l ts. If th e m e m o ry i s u se d to h o l d u nne e de d te m po rari e s i nste ad, th e q u al i ty o f th e si m u l ati o n w i l l su f f e r.)

E arl y i m pl e m e ntati o ns o f nu m e ri c array l i brari e s f ace d th i s pro bl e m and e nco u rag e d u se rs to u se co m pu te d assi g nm e nts (su ch as += , *= , and so f o rth ) i nste ad. T h e adv antag e o f th e se assi g nm e nts i s th at bo th th e arg u m e nt and th e de sti nati o n are pro v i de d by th e cal l e r, and h e nce no te m po rari e s are ne e de d. F o r e x am pl e , w e co u l d add SArray m e m be rs as f o l l o w s:

Page 380: CPlusPlus Templates The Complete Guide

// exprtmpl/sarrayops2.hpp // additive assignment of SArray template<class T> SArray<T>& SArray<T>::operator+= (SArray<T> const& b) { for (size_t k = 0; k<size(); ++k) { (*this)[k] += b[k]; } return *this; } // multiplicative assignment of SArray template<class T> SArray<T>& SArray<T>::operator*= (SArray<T> const& b) { for (size_t k = 0; k<size(); ++k) { (*this)[k] *= b[k]; } return *this; } // multiplicative assignment of scalar template<class T> SArray<T>& SArray<T>::operator*= (T const& s) { for (size_t k = 0; k<size(); ++k) { (*this)[k] *= s; } return *this; }

W i th o pe rato rs su ch as th e se , o u r e x am pl e co m pu tati o n co u l d be re w ri tte n as

// exprtmpl/sarray2.cpp #include "sarray2.hpp" #include "sarrayops1.hpp" #include "sarrayops2.hpp" int main() { SArray<double> x(1000), y(1000); … // process x = 1.2*x + x*y SArray<double> tmp(x); tmp *= y; x *= 1.2; x += tmp; }

C l e arl y , th e te ch ni q u e u si ng co m pu te d assi g nm e nts sti l l f al l s sh o rt:

• T h e no tati o n h as be co m e cl u m sy . • W e are sti l l l e f t w i th an u nne e de d te m po rary tmp. • T h e l o o p i s spl i t o v e r m u l ti pl e o pe rati o ns, re q u i ri ng a to tal o f

appro x i m ate l y 6 , 0 0 0 double e l e m e nts to be re ad f ro m m e m o ry and 4 , 0 0 0

Page 381: CPlusPlus Templates The Complete Guide

doubles to be w ri tte n to m e m o ry .

W h at w e re al l y w ant i s one " i de al l o o p" th at pro ce sse s th e w h o l e e x pre ssi o n f o r e ach i nde x :

int main() { SArray<double> x(1000), y(1000); … for (int idx = 0; idx<x.size(); ++idx) { x[idx] = 1.2*x[idx] + x[idx]*y[idx]; } }

No w w e ne e d no te m po rary array and w e h av e o nl y tw o m e m o ry re ads (x[idx] and y[idx]) and o ne m e m o ry w ri te (x[k]) pe r i te rati o n. A s a re su l t, th e m anu al l o o p re q u i re s o nl y appro x i m ate l y 2 , 0 0 0 m e m o ry re ads and 1 , 0 0 0 m e m o ry w ri te s.

G i v e n th at o n m o de rn, h i g h -pe rf o rm ance co m pu te r arch i te ctu re s m e m o ry bandw i dth i s th e l i m i ti ng f acto r f o r th e spe e d o f th e se so rts o f array o pe rati o ns, i t i s no t su rpri si ng th at i n practi ce th e pe rf o rm ance o f th e si m pl e o pe rato r o v e rl o adi ng appro ach e s sh o w n h e re i s o ne o r tw o o rde rs o f m ag ni tu de sl o w e r th an th e m anu al l y co de d l o o p. H o w e v e r, w e w o u l d l i k e to g e t th i s pe rf o rm ance w i th o u t th e cu m be rso m e and e rro r-pro ne e f f o rt o f w ri ti ng th e se l o o ps by h and o r u si ng a cl u m sy no tati o n.

Page 382: CPlusPlus Templates The Complete Guide

18.2 Encoding Expressions in Template Arguments

T h e k e y to re so l v i ng o u r pro bl e m i s no t to atte m pt to e v al u ate part o f an e x pre ssi o n u nti l th e w h o l e e x pre ssi o n h as be e n se e n (i n o u r e x am pl e , u nti l th e assi g nm e nt o pe rato r i s i nv o k e d). T h u s, be f o re th e e v al u ati o n w e m u st re co rd w h i ch o pe rati o ns are be i ng appl i e d to w h i ch o bj e cts. T h e o pe rati o ns are de te rm i ne d at co m pi l e ti m e and can th e re f o re be e nco de d i n te m pl ate arg u m e nts.

F o r o u r e x am pl e e x pre ssi o n

1.2*x + x*y;

th i s m e ans th at th e re su l t o f 1.2*x i s no t a ne w array bu t an o bj e ct th at re pre se nts e a c h v a l ue of x m ul t i p l i e d b y 1.2. S i m i l arl y , x*y m u st y i e l d e a c h e l e m e nt of x m ul t i p l i e d b y e a c h c or r e s p ondi ng e l e m e nt of y. F i nal l y , w h e n w e ne e d th e v al u e s o f th e re su l ti ng array , w e do th e co m pu tati o n th at w e sto re d f o r l ate r e v al u ati o n.

L e t' s l o o k at a co ncre te i m pl e m e ntati o n. W i th th i s i m pl e m e ntati o n w e transf o rm th e w ri tte n e x pre ssi o n

1.2*x + x*y;

i nto an o bj e ct w i th th e f o l l o w i ng ty pe :

A_Add< A_Mult<A_Scalar<double>,Array<double> >, A_Mult<Array<double>,Array<double> > >

W e co m bi ne a ne w f u ndam e ntal Array cl ass te m pl ate w i th cl ass te m pl ate s A_Scalar, A_Add , and A_Mult. Y o u m ay re co g ni z e a pre f i x re pre se ntati o n f o r th e sy ntax tre e co rre spo ndi ng to th i s e x pre ssi o n (se e F i g u re 1 8 .1 ). T h i s ne ste d te m pl ate -i d re pre se nts th e o pe rati o ns i nv o l v e d and th e ty pe s o f th e o bj e cts to w h i ch th e o pe rati o ns sh o u l d be appl i e d. A_Scalar i s pre se nte d l ate r bu t i s e sse nti al l y j u st a pl ace h o l de r f o r a scal ar i n an array e x pre ssi o n.

F i g u re 18 .1. Tree rep res en tati on of ex p res s i on 1.2*x+x*y

Page 383: CPlusPlus Templates The Complete Guide

18.2.1 Operands of the Expression Templates

T o co m pl e te th e re pre se ntati o n o f th e e x pre ssi o n, w e m u st sto re re f e re nce s to th e arg u m e nts i n e ach o f th e A_Add and A_Mult o bj e cts and re co rd th e v al u e o f th e scal ar i n th e A_Scalar o bj e ct (o r a re f e re nce th e re to ). H e re are po ssi bl e de f i ni ti o ns f o r th e co rre spo ndi ng o pe rands:

// exprtmpl/exprops1.hpp #include <stddef.h> #include <cassert> // include helper class traits template to select wether to refer to an // ''expression template node'' either ''by value'' or ''by reference.'' #include "exprops1a.hpp" // class for objects that represent the addition of two operands template <typename T, typename OP1, typename OP2> class A_Add { private: typename A_Traits<OP1>::ExprRef op1; // first operand typename A_Traits<OP2>::ExprRef op2; // second operand public: // constructor initializes references to operands A_Add (OP1 const& a, OP2 const& b) : op1(a), op2(b) { } // compute sum when value requested T operator[] (size_t idx) const { return op1[idx] + op2[idx]; } // size is maximum size size_t size() const { assert (op1.size()==0 || op2.size()==0 || op1.size()==op2.size()); return op1.size()!=0 ? op1.size() : op2.size(); } }; // class for objects that represent the multiplication of two operands template <typename T, typename OP1, typename OP2> class A_Mult {

Page 384: CPlusPlus Templates The Complete Guide

private: typename A_Traits<OP1>::ExprRef op1; // first operand typename A_Traits<OP2>::ExprRef op2; // second operand public: // constructor initializes references to operands A_Mult (OP1 const& a, OP2 const& b) : op1(a), op2(b) { } // compute product when value requested T operator[] (size_t idx) const { return op1[idx] * op2[idx]; } // size is maximum size size_t size() const { assert (op1.size()==0 || op2.size()==0 || op1.size()==op2.size()); return op1.size()!=0 ? op1.size() : op2.size(); } };

A s y o u can se e , w e adde d su bscri pti ng and si z e -q u e ry i ng o pe rati o ns th at al l o w u s to co m pu te th e si z e and th e v al u e s o f th e e l e m e nts f o r th e array re su l ti ng f ro m th e o pe rati o ns re pre se nte d by th e su btre e o f " no de s" ro o te d at th e g i v e n o bj e ct.

F o r o pe rati o ns i nv o l v i ng array s o nl y , th e si z e o f th e re su l t i s th e si z e o f e i th e r o pe rand. H o w e v e r, f o r o pe rati o ns i nv o l v i ng bo th an array and a scal ar, th e si z e o f th e re su l t i s th e si z e o f th e array o pe rand. T o di sti ng u i sh array o pe rands f ro m scal ar o pe rands, w e de f i ne a si z e o f z e ro f o r scal ars. T h e A_Scalar te m pl ate i s th e re f o re de f i ne d as f o l l o w s:

// exprtmpl/exprscalar.hpp // class for objects that represent scalars template <typename T> class A_Scalar { private: T const& s; // value of the scalar public: // constructor initializes value A_Scalar (T const& v) : s(v) { } // for index operations the scalar is the value of each element T operator[] (size_t) const { return s; } // scalars have zero as size size_t size() const { return 0; };

Page 385: CPlusPlus Templates The Complete Guide

};

No te th at scal ars al so pro v i de an i nde x o pe rato r. Insi de th e e x pre ssi o n, th e y re pre se nt an array w i th th e sam e scal ar v al u e f o r e ach i nde x .

Y o u pro babl y saw th at th e o pe rato r cl asse s u se d a h e l pe r cl ass A_Traits to de f i ne th e m e m b e rs f o r th e o pe rands:

typename A_Traits<OP1>::ExprRef op1; // first operand typename A_Traits<OP2>::ExprRef op2; // second operand

T h i s i s ne ce ssary be cau se o f th e f o l l o w i ng : In g e ne ral , w e can de cl are th e m to be re f e re nce s be cau se m o st te m po rary no de s are bo u nd i n th e to p-l e v e l e x pre ssi o n and th e re f o re l i v e u nti l th e e nd o f th e e v al u ati o n o f th at co m pl e te e x pre ssi o n. T h e o ne e x ce pti o n are th e A_Scalar no de s. T h e y are bo u nd w i th i n th e o pe rato r f u ncti o ns and m i g h t no t l i v e u nti l th e e nd o f th e e v al u ati o n o f th e co m pl e te e x pre ssi o n. T h u s, to av o i d th at th e m e m be rs re f e r to scal ars th at do n' t e x i st any m o re , f o r scal ars th e o pe rands h av e to g e t co pi e d " by v al u e ." In o th e r w o rds, w e ne e d m e m b e rs th at are

• co nstant re f e re nce s i n g e ne ral : • • OP1 const& op1; // refer to first operand by reference

OP2 const& op2; // refer to second operand by reference

• bu t o rdi nary v al u e s f o r scal ars: •

• OP1 op1; // refer to first operand by value OP2 op2; // refer to second operand by value

T h i s i s a pe rf e ct appl i cati o n o f trai ts cl asse s. T h e trai ts cl ass de f i ne s a ty pe to be a co nstant re f e re nce i n g e ne ral , bu t an o rdi nary v al u e f o r scal ars:

// exprtmpl/exprops1a.hpp /* helper traits class to select how to refer to an ''expression template node'' * - in general: by reference * - for scalars: by value */ template <typename T> class A_Scalar; // primary template template <typename T> class A_Traits { public: typedef T const& ExprRef; // type to refer to is constant reference };

Page 386: CPlusPlus Templates The Complete Guide

// partial specialization for scalars template <typename T> class A_Traits<A_Scalar<T> > { public: typedef A_Scalar<T> ExprRef; // type to refer to is ordinary value };

No te th at si nce A_Scalar o bj e cts re f e r to scal ars i n th e to p-l e v e l e x pre ssi o n, th o se scal ars can u se re f e re nce ty pe s.

18.2.2 The Array Type

W i th o u r abi l i ty to e nco de e x pre ssi o ns u si ng l i g h tw e i g h t e x pre ssi o n te m pl ate s, w e m u st no w cre ate an Array ty pe th at co ntro l s actu al sto rag e and th at k no w s abo u t th e e x pre ssi o n te m pl ate s. H o w e v e r, i t i s al so u se f u l f o r e ng i ne e ri ng pu rpo se s to k e e p as si m i l ar as po ssi bl e th e i nte rf ace f o r a re al array w i th sto rag e and o ne f o r a re pre se ntati o n o f an e x pre ssi o n th at re su l ts i n an array . T o th i s e nd, w e de cl are th e Array te m pl ate as f o l l o w s:

template <typename T, typename Rep = SArray<T> > class Array;

T h e ty pe Rep can be SArray i f Array i s a re al array o f sto rag e , [1] o r i t can be th e ne ste d te m pl ate -i d su ch as A_Add o r A_Mult th at e nco de s an e x pre ssi o n. E i th e r w ay w e are h andl i ng Array i nstanti ati o ns, w h i ch co nsi de rabl y si m pl i f y o u r l ate r de al i ng s. In f act, e v e n th e de f i ni ti o n o f th e Array te m pl ate ne e ds no spe ci al i z ati o ns to di sti ng u i sh th e tw o case s, al th o u g h so m e o f th e m e m b e rs canno t be i nstanti ate d f o r ty pe s l i k e A_Mult su bsti tu te d f o r Rep.

[1] It i s co nv e ni e nt to re u se th e pre v i o u sl y de v e l o pe d SArray h e re , bu t i n an i ndu stri al -stre ng th l i brary , a spe ci al -pu rpo se i m pl e m e ntati o n m ay be pre f e rabl e be cau se w e w o n' t u se al l th e f e atu re s o f SArray.

H e re i s th e de f i ni ti o n. T h e f u ncti o nal i ty i s l i m i te d ro u g h l y to w h at w as pro v i de d by o u r SArray te m pl ate , al th o u g h o nce th e co de i s u nde rsto o d, i t i s no t h ard to add to th at f u ncti o nal i ty :

// exprtmpl/exprarray.hpp #include <stddef.h> #include <cassert> #include "sarray1.hpp" template <typename T, typename Rep = SArray<T> > class Array { private:

Page 387: CPlusPlus Templates The Complete Guide

Rep expr_rep; // (access to) the data of the array public: // create array with initial size explicit Array (size_t s) : expr_rep(s) { } // create array from possible representation Array (Rep const& rb) : expr_rep(rb) { } // assignment operator for same type Array& operator= (Array const& b) { assert(size()==b.size()); for (size_t idx = 0; idx<b.size(); ++idx) { expr_rep[idx] = b[idx]; } return *this; } // assignment operator for arrays of different type template<typename T2, typename Rep2> Array& operator= (Array<T2, Rep2> const& b) { assert(size()==b.size()); for (size_t idx = 0; idx<b.size(); ++idx) { expr_rep[idx] = b[idx]; } return *this; } // size is size of represented data size_t size() const { return expr_rep.size(); } // index operator for constants and variables T operator[] (size_t idx) const { assert(idx<size()); return expr_rep[idx]; } T& operator[] (size_t idx) { assert(idx<size()); return expr_rep[idx]; } // return what the array currently represents Rep const& rep() const { return expr_rep; } Rep& rep() { return expr_rep; } };

A s y o u can se e , m any o pe rati o ns are si m pl y f o rw arde d to th e u nde rl y i ng Rep o bj e ct. H o w e v e r, w h e n co py i ng ano th e r array , w e m u st tak e i nto acco u nt th e po ssi bi l i ty th at th e o th e r array i s re al l y bu i l t o n an e x pre ssi o n te m pl ate . T h u s, w e

Page 388: CPlusPlus Templates The Complete Guide

param e te ri z e th e se co py o pe rati o ns i n te rm s o f th e u nde rl y i ng Rep re pre se ntati o n.

18.2.3 The Operators

W e h av e m o st o f th e m ach i ne ry i n pl ace to h av e e f f i ci e nt nu m e ri c o pe rato rs f o r o u r nu m e ri c Array te m pl ate , e x ce pt th e o pe rato rs th e m se l v e s. A s i m pl i e d e arl i e r, th e se o pe rato rs o nl y asse m bl e th e e x pre ssi o n te m pl ate o bj e cts—th e y do n' t actu al l y e v al u ate th e re su l ti ng array s.

F o r e ach o rdi nary bi nary o pe rato r w e m u st i m pl e m e nt th re e v e rsi o ns: array -array , array -scal ar, and scal ar-array . T o be abl e to co m pu te o u r i ni ti al v al u e w e ne e d, f o r e x am pl e , th e f o l l o w i ng o pe rato rs:

// exprtmpl/exprops2.hpp // addition of two Arrays template <typename T, typename R1, typename R2> Array<T,A_Add<T,R1,R2> > operator+ (Array<T,R1> const& a, Array<T,R2> const& b) { return Array<T,A_Add<T,R1,R2> > (A_Add<T,R1,R2>(a.rep(),b.rep())); } // multiplication of two Arrays template <typename T, typename R1, typename R2> Array<T, A_Mult<T,R1,R2> > operator* (Array<T,R1> const& a, Array<T,R2> const& b) { return Array<T,A_Mult<T,R1,R2> > (A_Mult<T,R1,R2>(a.rep(), b.rep())); } // multiplication of scalar and Array template <typename T, typename R2> Array<T, A_Mult<T,A_Scalar<T>,R2> > operator* (T const& s, Array<T,R2> const& b) { return Array<T,A_Mult<T,A_Scalar<T>,R2> > (A_Mult<T,A_Scalar<T>,R2>(A_Scalar<T>(s), b.rep())); } // multiplication of Array and scalar // addition of scalar and Array // addition of Array and scalar …

T h e de cl arati o n o f th e se o pe rato rs i s so m e w h at cu m be rso m e (as can be se e n f ro m th e se e x am pl e s), bu t th e f u ncti o ns re al l y do n' t do m u ch . F o r e x am pl e , th e pl u s o pe rato r f o r tw o array s f i rst cre ate s an A_Add<> o bj e ct th at re pre se nts th e o pe rato r and th e o pe rands

A_Add<T,R1,R2>(a.rep(),b.rep())

Page 389: CPlusPlus Templates The Complete Guide

and w raps th i s o bj e ct i n an Array o bj e ct so th at w e can u se th e re su l t as any o th e r o bj e ct th at re pre se nts data o f an array :

return Array<T,A_Add<T,R1,R2> > (… );

F o r scal ar m u l ti pl i cati o n, w e u se th e A_Scalar te m pl ate to cre ate th e A_Mult o bj e ct

A_Mult<T,A_Scalar<T>,R2>(A_Scalar<T>(s), b.rep())

and w rap ag ai n:

return Array<T,A_Mult<T,A_Scalar<T>,R2> > (… );

O th e r no nm e m be r bi nary o pe rato rs are so si m i l ar th at m acro s can be u se d to co v e r m o st o pe rato rs w i th re l ati v e l y l i ttl e so u rce co de . A no th e r (sm al l e r) m acro co u l d be u se d f o r no nm e m be r u nary o pe rato rs.

18.2.4 Review

O n f i rst di sco v e ry o f th e e x pre ssi o n te m pl ate i de a, th e i nte racti o n o f th e v ari o u s de cl arati o ns and de f i ni ti o ns can be dau nti ng . H e nce , a to p-do w n re v i e w o f w h at h appe ns w i th o u r e x am pl e co de m ay h e l p cry stal l i z e u nde rstandi ng . T h e co de w e w i l l anal y z e i s th e f o l l o w i ng (y o u can f i nd i t as part o f meta/exprmain.cpp):

int main() { Array<double> x(1000), y(1000); … x = 1.2*x + x*y; }

B e cau se th e Rep arg u m e nt i s o m i tte d i n th e de f i ni ti o n o f x and y , i t i s se t to th e de f au l t, w h i ch i s SArray<double>. S o , x and y are array s w i th " re al " sto rag e and no t j u st re co rdi ng s o f o pe rati o ns.

W h e n parsi ng th e e x pre ssi o n

1.2*x + x*y

th e co m pi l e r f i rst appl i e s th e l e f tm o st * o pe rati o n, w h i ch i s a scal ar-array o pe rato r. O v e rl o ad re so l u ti o n th u s se l e cts th e scal ar-array f o rm o f operator*:

Page 390: CPlusPlus Templates The Complete Guide

template <typename T, typename R2> Array<T, A_Mult<T,A_Scalar<T>,R2> > operator* (T const& s, Array<T,R2> const& b) { return Array<T,A_Mult<T,A_Scalar<T>,R2> > (A_Mult<T,A_Scalar<T>,R2>(A_Scalar<T>(s), b.rep())); }

T h e o pe rand ty pe s are double and Array<double, SArray<double> >. T h u s, th e ty pe o f th e re su l t i s

Array<double, A_Mult<double, A_Scalar<double>, SArray<double> > >

T h e re su l t v al u e i s co nstru cte d to re f e re nce an A_Scalar<double> o bj e ct co nstru cte d f ro m th e double v al u e 1.2 and th e SArray<double> re pre se ntati o n o f th e o bj e ct x.

Ne x t, th e se co nd m u l ti pl i cati o n i s e v al u ate d: It i s an array -array o pe rati o n x*y. T h i s ti m e w e u se th e appro pri ate operator*:

template <typename T, typename R1, typename R2> Array<T, A_Mult<T,R1,R2> > operator* (Array<T,R1> const& a, Array<T,R2> const& b) { return Array<T,A_Mult<T,R1,R2> > (A_Mult<T,R1,R2>(a.rep(), b.rep())); }

T h e o pe rand ty pe s are bo th Array<double, SArray<double> > , so th e re su l t ty pe i s

Array<double, A_Mult<double, SArray<double>, SArray<double> > >

T h i s ti m e th e w rappe d A_Mult o bj e ct re f e rs to tw o SArray<double> re pre se ntati o ns: th e o ne o f x and th e o ne o f y.

F i nal l y , th e + o pe rati o n i s e v al u ate d. It i s ag ai n an array -array o pe rati o n, and th e o pe rand ty pe s are th e re su l t ty pe s th at w e j u st de du ce d. S o , w e i nv o k e th e array -array o pe rato r +:

template <typename T, typename R1, typename R2> Array<T,A_Add<T,R1,R2> > operator+ (Array<T,R1> const& a, Array<T,R2> const& b) { return Array<T,A_Add<T,R1,R2> > (A_Add<T,R1,R2>(a.rep(),b.rep())); }

T i s su bsti tu te d w i th double w h e re as R1 i s su bsti tu te d w i th

Page 391: CPlusPlus Templates The Complete Guide

A_Mult<double, A_Scalar<double>, SArray<double> >

and R2 i s su bsti tu te d w i th

A_Mult<double, SArray<double>, SArray<double> >

H e nce , th e ty pe o f th e e x pre ssi o n to th e ri g h t o f th e assi g nm e nt to k e n i s

Array<double, A_Add<double, A_Mult<double, A_Scalar<double>, SArray<double> >, A_Mult<double, SArray<double>, SArray<double>>>>

T h i s ty pe i s m atch e d to th e assi g nm e nt o pe rato r te m pl ate o f th e Array te m pl ate :

template <typename T, typename Rep = SArray<T> > class Array { public: … // assignment operator for arrays of different type template<typename T2, typename Rep2> Array& operator= (Array<T2, Rep2> const& b) { assert(size()==b.size()); for (size_t idx = 0; idx<b.size(); ++idx) { expr_rep[idx] = b[idx]; } return *this; } … };

T h e assi g nm e nt o pe rato r co m pu te s e ach e l e m e nt o f th e de sti nati o n x by appl y i ng th e su bscri pt o pe rato r to th e re pre se ntati o n o f th e ri g h t si de , th e ty pe o f w h i ch i s

A_Add<double, A_Mult<double, A_Scalar<double>, SArray<double> >, A_Mult<double, SArray<double>, SArray<double> > > >

C are f u l l y traci ng th i s su bscri pt o pe rato r sh o w s th at f o r a g i v e n su bscri pt idx, i t co m pu te s

(1.2*x[idx]) + (x[idx]*y[idx])

w h i ch i s e x actl y w h at w e w ant.

18.2.5 Expression Templates Assignments

It i s no t po ssi bl e to i nstanti ate w ri te o pe rati o ns f o r an array w i th a Rep arg u m e nt

Page 392: CPlusPlus Templates The Complete Guide

th at i s bu i l t o n o u r e x am pl e A_Mult and A_Add e x pre ssi o n te m pl ate s. (Inde e d, i t m ak e s no se nse to w ri te a+b = c.) H o w e v e r, i t i s e nti re l y re aso nabl e to w ri te o th e r e x pre ssi o n te m pl ate s f o r w h i ch assi g nm e nt to th e re su l t i s po ssi bl e . F o r e x am pl e , i nde x i ng w i th an array o f i nte g ral v al u e s w o u l d i ntu i ti v e l y co rre spo nd to su bse t se l e cti o n. In o th e r w o rds, th e e x pre ssi o n

x[y] = 2*x[y];

sh o u l d m e an th e sam e as

for (size_t idx = 0; idx<y.size(); ++idx) { x[y[idx]] = 2*x[y[idx]]; }

E nabl i ng th i s i m pl i e s th at an array bu i l t o n an e x pre ssi o n te m pl ate be h av e s l i k e an l v al u e (th at i s, i s " w ri tabl e " ). T h e e x pre ssi o n te m pl ate co m po ne nt f o r th i s i s no t f u ndam e ntal l y di f f e re nt f ro m , say , A_Mult, e x ce pt th at bo th const and no n-const v e rsi o ns o f th e su bscri pt o pe rato rs are pro v i de d and th e y re tu rn l v al u e s (re f e re nce s):

// exprtmpl/exprops3.hpp template<typename T, typename A1, typename A2> class A_Subscript { public: // constructor initializes references to operands A_Subscript (A1 const & a, A2 const & b) : a1(a), a2(b) { } // process subscription when value requested T operator[] (size_t idx) const { return a1[a2[idx]]; } T& operator[] (size_t idx) { return a1[a2[idx]]; } // size is size of inner array size_t size() const { return a2.size(); } private: A1 const & a1; // reference to first operand A2 const & a2; // reference to second operand };

T h e e x te nde d su bscri pt o pe rato r w i th su bse t se m anti cs th at w as su g g e ste d e arl i e r w o u l d re q u i re th at addi ti o nal su bscri pt o pe rato rs be adde d to th e Array

Page 393: CPlusPlus Templates The Complete Guide

te m pl ate . O ne o f th e se o pe rato rs co u l d be de f i ne d as f o l l o w s (a co rre spo ndi ng const v e rsi o n w o u l d pre su m abl y al so be ne e de d):

// exprtmpl/exprops4.hpp template<typename T, typename R1, typename R2> Array<T,A_Subscript<T,R1,R2> > Array<T,R1>::operator[] (Array<T,R2> const & b) { return Array<T,A_Subscript<T,R1,R2> > (A_Subscript<T,R1,R2>(a.rep(),b.rep())); }

Page 394: CPlusPlus Templates The Complete Guide

18.3 Performance and Limitations of Expression Templates

T o j u sti f y th e co m pl e x i ty o f th e e x pre ssi o n te m pl ate i de a, w e h av e al re ady i nv o k e d g re atl y e nh ance d pe rf o rm ance o n array w i se o pe rati o ns. A s y o u trace w h at h appe ns w i th th e e x pre ssi o n te m pl ate s, y o u ' l l f i nd th at m any sm al l i nl i ne f u ncti o ns cal l e ach o th e r and th at m any sm al l e x pre ssi o n te m pl ate o bj e cts are al l o cate d o n th e cal l stack . T h e o pti m i z e r m u st pe rf o rm co m pl e te i nl i ni ng and e l i m i nati o n o f th e sm al l o bj e cts to pro du ce co de th at pe rf o rm s as w e l l as m anu al l y co de d l o o ps. T h e l atte r f e at i s sti l l rare am o ng C + + co m pi l e rs at th e ti m e o f th i s w ri ti ng .

T h e e x pre ssi o n te m pl ate s te ch ni q u e do e s no t re so l v e al l th e pro bl e m ati c si tu ati o ns i nv o l v i ng nu m e ri c o pe rati o ns o n array s. F o r e x am pl e , i t do e s no t w o rk f o r m atri x -v e cto r m u l ti pl i cati o ns o f th e f o rm

x = A*x;

w h e re x i s a co l u m n v e cto r o f si z e n and A i s an n-by -n m atri x . T h e pro bl e m h e re i s th at a te m po rary m u st be u se d be cau se e ach e l e m e nt o f th e re su l t can de pe nd o n e ach e l e m e nt o f th e o ri g i nal x. U nf o rtu nate l y , th e e x pre ssi o n te m pl ate l o o p u pdate s th e f i rst e l e m e nt o f x ri g h t aw ay and th e n u se s th at ne w l y co m pu te d e l e m e nt to co m pu te th e se co nd e l e m e nt, w h i ch i s w ro ng . T h e sl i g h tl y di f f e re nt e x pre ssi o n

x = A*y;

o n th e o th e r h and, do e s no t ne e d a te m po rary i f x and y are n' t al i ase s f o r e ach o th e r, w h i ch i m pl i e s th at a so l u ti o n w o u l d h av e to k no w th e re l ati o nsh i p o f th e o pe rands at ru n ti m e . T h i s i n tu rn su g g e sts cre ati ng a ru n-ti m e stru ctu re th at re pre se nts th e e x pre ssi o n tre e i nste ad o f e nco di ng th e tre e i n th e ty pe o f th e e x pre ssi o n te m pl ate . T h i s appro ach w as pi o ne e re d by th e Ne w M at l i brary o f R o be rt D av i e s (se e [Ne w M at]). It w as k no w n l o ng be f o re e x pre ssi o n te m pl ate s w e re de v e l o pe d.

E x pre ssi o n te m pl ate s are n' t l i m i te d to nu m e ri c co m pu tati o ns e i th e r. A n i ntri g u i ng appl i cati o n, f o r e x am pl e , i s J aak k o J ä rv i and G ary P o w e l l ' s L a m b da L i b r a r y (se e [L am bdaL i b]). T h i s l i brary u se s standard l i brary f u ncti o n o bj e cts as e x pre ssi o n o bj e cts. F o r e x am pl e , i t al l o w s u s to w ri te th e f o l l o w i ng :

void lambda_demo (std::vector<long*> & ones) { std::sort(ones.begin(), ones.end(), *_1 > *_2);

Page 395: CPlusPlus Templates The Complete Guide

}

T h i s sh o rt co de e x ce rpt so rts an array i n i ncre asi ng o rde r o f th e v al u e o f w h at i ts e l e m e nts r e f e r t o. W i th o u t th e L am bda l i brary , w e ' d h av e to de f i ne a si m pl e (bu t cu m be rso m e ) spe ci al -pu rpo se f u ncto r ty pe . Inste ad, w e can no w u se si m pl e i nl i ne sy ntax to e x pre ss th e o pe rati o ns w e w ant to appl y . In o u r e x am pl e , _1 and _2 are pl ace h o l de rs pro v i de d by th e L am bda l i brary . T h e y co rre spo nd to e l e m e ntary e x pre ssi o n o bj e cts th at are al so f u ncto rs. T h e y can th e n be u se d to co nstru ct m o re co m pl e x e x pre ssi o ns u si ng th e te ch ni q u e s de v e l o pe d i n th i s ch apte r.

Page 396: CPlusPlus Templates The Complete Guide

18.4 Afternotes

E x pre ssi o n te m pl ate s w e re de v e l o pe d i nde pe nde ntl y by T o dd V e l dh u i z e n and D av i d V ande v o o rde (T o dd co i ne d th e te rm ) at a ti m e w h e n m e m b e r te m pl ate s w e re no t y e t part o f th e C + + pro g ram m i ng l ang u ag e (and i t se e m e d at th e ti m e th at th e y w o u l d ne v e r be adde d to C + + ). T h i s cau se d so m e pro bl e m s i n i m pl e m e nti ng th e assi g nm e nt o pe rato r: It co u l d no t be param e te ri z e d f o r th e e x pre ssi o n te m pl ate . O ne te ch ni q u e to w o rk aro u nd th i s co nsi ste d o f i ntro du ci ng i n th e e x pre ssi o n te m pl ate s a co nv e rsi o n o pe rato r to a Copier cl ass param e te ri z e d w i th th e e x pre ssi o n te m pl ate bu t i nh e ri ti ng f ro m a base cl ass th at w as param e te ri z e d o nl y i n th e e l e m e nt ty pe . T h i s base cl ass th e n pro v i de d a (v i rtu al ) copy_to i nte rf ace to w h i ch th e assi g nm e nt o pe rato r co u l d re f e r. H e re i s a sk e tch o f th e m e ch ani sm (w i th th e te m pl ate nam e s u se d i n th i s ch apte r):

template<typename T> class CopierInterface { public: virtual void copy_to(Array<T, SArray<T> >&) const; }; template<typename T, typename X> class Copier : public CopierBase<T> { public: Copier(X const &x): expr(x) {} virtual void copy_to(Array<T, SArray<T> >&) const { // implementation of assignment loop … } private: X const &expr; }; template<typename T, typename Rep = SArray<T> > class Array { public: // delegated assignment operator Array<T, Rep>& operator=(CopierBase<T> const &b) { b.copy_to(rep); }; … }; template<typename T, typename A1, typename A2> class A_mult { public: operator Copier<T, A_Mult<T, A1, A2> >(); … };

T h i s adds ano th e r l e v e l o f co m pl e x i ty and so m e addi ti o nal ru n-ti m e co st to e x pre ssi o n te m pl ate s, bu t e v e n so th e re su l ti ng pe rf o rm ance be ne f i ts w e re

Page 397: CPlusPlus Templates The Complete Guide

i m pre ssi v e at th e ti m e .

T h e C + + standard l i brary co ntai ns a cl ass te m pl ate valarray th at w as m e ant to be u se d f o r appl i cati o ns th at w o u l d j u sti f y th e te ch ni q u e s u se d f o r th e Array te m pl ate de v e l o pe d i n th i s ch apte r. A pre cu rso r o f valarray h ad be e n de si g ne d w i th th e i nte nti o n th at co m pi l e rs ai m i ng at th e m ark e t f o r sci e nti f i c co m pu tati o n w o u l d re co g ni z e th e array ty pe and u se h i g h l y o pti m i z e d i nte rnal co de f o r th e i r o pe rati o ns. S u ch co m pi l e rs w o u l d h av e " u nde rsto o d" th e ty pe s i n so m e se nse . H o w e v e r, th i s ne v e r h appe ne d (i n part be cau se th e m ark e t i n q u e sti o n i s re l ati v e l y sm al l and i n part be cau se th e pro bl e m g re w i n co m pl e x i ty as valarray be cam e a te m pl ate ). S o m e ti m e af te r th e e x pre ssi o n te m pl ate te ch ni q u e w as di sco v e re d, o ne o f u s (V ande v o o rde ) su bm i tte d to th e C + + co m m i tte e a pro po sal th at tu rne d valarray e sse nti al l y i nto th e Array te m pl ate w e de v e l o pe d (w i th m any be l l s and w h i stl e s i nspi re d by th e e x i sti ng valarray f u ncti o nal i ty ). T h e pro po sal w as th e f i rst ti m e th at th e co nce pt o f th e Rep param e te r w as do cu m e nte d. P ri o r to th i s, th e array s w i th actu al sto rag e and th e e x pre ssi o n te m pl ate pse u do -array s w e re di f f e re nt te m pl ate s. W h e n cl i e nt co de i ntro du ce d a f u ncti o n foo() acce pti ng an array —f o r e x am pl e ,

double foo(Array<double> const&);

cal l i ng foo(1.2*x) f o rce d th e co nv e rsi o n f o r th e e x pre ssi o n te m pl ate to an array w i th actu al sto rag e , e v e n w h e n th e o pe rati o ns appl i e d to th at arg u m e nt di d no t re q u i re a te m po rary . W i th e x pre sssi o n te m pl ate s e m be dde d i n th e Rep arg u m e nt i t i s po ssi bl e i nste ad to de cl are

template<typename R> double foo(Array<double, R> const&);

and no co nv e rsi o n h appe ns u nl e ss o ne i s actu al l y ne e de d.

T h e valarray pro po sal cam e l ate i n th e C + + standardi z ati o n pro ce ss and practi cal l y re w ro te al l th e te x t re g ardi ng valarray i n th e standard. It w as re j e cte d as a re su l t, and i nste ad, a f e w tw e ak s w e re adde d to th e e x i sti ng te x t to al l o w i m pl e m e ntati o ns base d o n e x pre ssi o n te m pl ate s. H o w e v e r, th e e x pl o i tati o n o f th i s al l o w ance re m ai ns m u ch m o re cu m be rso m e th an w h at w as di scu sse d h e re . A t th e ti m e o f th i s w ri ti ng , no su ch i m pl e m e ntati o n i s k no w n, and standard valarrays are , g e ne ral l y spe ak i ng , q u i te i ne f f i ci e nt at pe rf o rm i ng th e o pe rati o ns f o r w h i ch th e y w e re de si g ne d.

F i nal l y , i t i s w o rth o bse rv i ng h e re th at m any o f th e pi o ne e ri ng te ch ni q u e s pre se nte d i n th i s ch apte r, as w e l l as w h at l ate r be cam e k no w n as th e S T L , [2 ] w e re al l o ri g i nal l y i m pl e m e nte d o n th e sam e co m pi l e r: v e rsi o n 4 o f th e B o rl and

Page 398: CPlusPlus Templates The Complete Guide

C + + co m pi l e r. T h i s w as pe rh aps th e f i rst co m pi l e r th at m ade te m pl ate pro g ram m i ng w i de l y av ai l abl e to th e C + + pro g ram m i ng co m m u ni ty .

[2 ] T h e S T L o r s t a nda r d t e m p l a t e l i b r a r y re v o l u ti o ni z e d th e w o rl d o f C + + l i brari e s and w as l ate r m ade part o f th e C + + standard l i brary (se e [J o su tti sS tdL i b]).

Page 399: CPlusPlus Templates The Complete Guide

Part IV: Advanced Applications

T e m pl ate s can be u se d to de v e l o p e l abo rate l i brari e s o f e l e m e nts th at co nne ct i n se am l e ss w ay s. No nte m pl ate l i brari e s can o f te n do su ch th i ng s to o . H o w e v e r, w h e n i t co m e s to sm al l , f ai rl y si m pl e u ti l i ti e s th at m ak e e v e ry day pro g ram m i ng e asi e r, tradi ti o nal pro ce du ral o r o bj e ct-o ri e nte d l i brari e s are no t al w ay s v i abl e be cau se th e o v e rh e ad ne e de d to i nv o k e th e si m pl e f u ncti o nal i ty i s di spro po rti o nate to th e f aci l i ty o f f e re d. T h e C pre pro ce sso r al l o w s so m e o f th e se " si m pl e ne e ds" to be addre sse d, bu t o f te n i t i s no t q u i te ade q u ate f o r th e task s at h and.

In th i s part w e e x pl o re so m e sm al l stand-al o ne u ti l i ti e s f o r w h i ch te m pl ate s are an i de al m e ans o f i m pl e m e ntati o n:

• A f ram e w o rk f o r ty pe cl assi f i cati o n • S m art P o i nte rs • T u pl e s • F u ncto rs

O u r g o al i s to de m o nstrate th e te ch ni q u e s di scu sse d e arl i e r. W e co m bi ne th e m and m o di f y th e m to cre ate g e nu i ne l y u se f u l so f tw are co m po ne nts. H o w e v e r, o u r m ai n to pi c i s sti l l C + + T e m p l a t e s and no t (f o r e x am pl e ) th e de v e l o pm e nt o f a co m pl e te C + + l i brary . W e h o pe th e co de w e pre se nt i s a u se f u l tu to ri al and so u rce o f i nspi rati o n f o r C + + l i brary w ri te rs, bu t w e do n' t cl ai m th at i t i s th e be st ch o i ce f o r o f f -th e -sh e l f co m po ne nts.

Page 400: CPlusPlus Templates The Complete Guide

Chapter 19. Type Classification

It i s so m e ti m e s u se f u l to be abl e to k no w w h e th e r a te m pl ate param e te r i s a bu i l t-i n ty pe , a po i nte r ty pe , o r a cl ass ty pe , and so f o rth . In th e f o l l o w i ng se cti o ns w e de v e l o p a g e ne ral -pu rpo se ty pe te m pl ate th at al l o w s u s to de te rm i ne v ari o u s pro pe rti e s o f a g i v e n ty pe . A s a re su l t w e w i l l be abl e to w ri te co de l i k e th e f o l l o w i ng :

if (TypeT<T>::IsPtrT) { … } else if (TypeT<T>::IsClassT) { … }

F u rth e rm o re , e x pre ssi o ns su ch as TypeT<T>::IsPtrT w i l l be B o o l e an co nstants th at are v al i d no nty pe te m pl ate arg u m e nts. In tu rn, th i s al l o w s th e co nstru cti o n o f m o re so ph i sti cate d and m o re po w e rf u l te m pl ate s th at spe ci al i z e th e i r be h av i o r o n th e pro pe rti e s o f th e i r ty pe arg u m e nts.

Page 401: CPlusPlus Templates The Complete Guide

19.1 Determining Fundamental Types

T o start, l e t' s de v e l o p a te m pl ate to de te rm i ne w h e th e r a ty pe i s a f u ndam e ntal ty pe . B y de f au l t, w e assu m e a ty pe i s no t f u ndam e ntal , and w e spe ci al i z e th e te m pl ate f o r th e f u ndam e ntal case s:

// types/type1.hpp // primary template: in general T is no fundamental type template <typename T> class IsFundaT { public: enum{ Yes = 0, No = 1}; }; // macro to specialize for fundamental types #define MK_FUNDA_TYPE(T) \ template<> class IsFundaT<T> { \ public: \ enum { Yes = 1, No = 0 }; \ }; MK_FUNDA_TYPE(void) MK_FUNDA_TYPE(bool) MK_FUNDA_TYPE(char) MK_FUNDA_TYPE(signed char) MK_FUNDA_TYPE(unsigned char) MK_FUNDA_TYPE(wchar_t) MK_FUNDA_TYPE(signed short) MK_FUNDA_TYPE(unsigned short) MK_FUNDA_TYPE(signed int) MK_FUNDA_TYPE(unsigned int) MK_FUNDA_TYPE(signed long) MK_FUNDA_TYPE(unsigned long) #if LONGLONG_EXISTS MK_FUNDA_TYPE(signed long long) MK_FUNDA_TYPE(unsigned long long) #endif // LONGLONG_EXISTS MK_FUNDA_TYPE(float) MK_FUNDA_TYPE(double) MK_FUNDA_TYPE(long double) #undef MK_FUNDA_TYPE

T h e pri m ary te m pl ate de f i ne s th e g e ne ral case . T h at i s, i n g e ne ral , IsFundaT<T >::Yes w i l l y i e l d 0 (o r false):

template <typename T> class IsFundaT {

Page 402: CPlusPlus Templates The Complete Guide

public: enum{ Yes = 0, No = 1 }; };

F o r e ach f u ndam e ntal ty pe a spe ci al i z ati o n i s de f i ne d so th at IsFundaT<T >::Yes w i l l y i e l d 1 (o r true). T h i s i s do ne by de f i ni ng a m acro th at e x pands th e ne ce ssary co de . F o r e x am pl e ,

MK_FUNDA_TYPE(bool)

e x pands to th e f o l l o w i ng :

template<> class IsFundaT<bool> { public: enum{ Yes = 1, No = 0 }; };

T h e f o l l o w i ng pro g ram de m o nstrate s a po ssi bl e u se o f th i s te m pl ate :

// types/type1test.cpp #include <iostream> #include "type1.hpp" template <typename T> void test (T const& t) { if (IsFundaT<T>::Yes) { std::cout << "T is fundamental type" << std::endl; } else { std::cout << "T is no fundamental type" << std::endl; } } class MyType { }; int main() { test(7); test(MyType()); }

It h as th e f o l l o w i ng o u tpu t:

T is fundamental type T is no fundamental type

In th e sam e w ay , w e can de f i ne ty pe f u ncti o ns IsIntegralT and IsFloatingT to i de nti f y w h i ch o f th e se ty pe s are i nte g ral scal ar ty pe s and w h i ch are f l o ati ng -

Page 403: CPlusPlus Templates The Complete Guide

po i nt scal ar ty pe s.

Page 404: CPlusPlus Templates The Complete Guide

19.2 Determining Compound Types

C o m po u nd ty pe s are ty pe s co nstru cte d f ro m o th e r ty pe s. S i m pl e co m po u nd ty pe s i ncl u de pl ai n ty pe s, po i nte r ty pe s, re f e re nce ty pe s, and e v e n array ty pe s. T h e y are co nstru cte d f ro m a si ng l e base ty pe . C l ass ty pe s and f u ncti o n ty pe s are al so co m po u nd ty pe s, bu t th e i r co m po si ti o n can i nv o l v e m u l ti pl e ty pe s (f o r param e te rs o r m e m be rs). S i m pl e co m po u nd ty pe s can be cl assi f i e d u si ng parti al spe ci al i z ati o n. W e start w i th a g e ne ri c de f i ni ti o n o f a trai ts cl ass de scri bi ng co m po u nd ty pe s o th e r th an cl ass ty pe s and e nu m e rati o n ty pe s (th e l atte r are tre ate d se parate l y ):

// types/type2.hpp template<typename T> class CompoundT { // primary template public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 0, IsPtrMemT = 0 }; typedef T BaseT; typedef T BottomT; typedef CompoundT<void> ClassT; };

T h e m e m b e r ty pe BaseT i s a sy no ny m f o r th e i m m e di ate ty pe o n w h i ch th e te m pl ate param e te r ty pe T bu i l ds. BottomT, o n th e o th e r h and, re f e rs to th e u l ti m ate no npo i nte r, no nre f e re nce , and no narray ty pe o n w h i ch T i s bu i l t. F o r e x am pl e , i f T i s int** , th e n BaseT w o u l d be int*, and BottomT w o u l d be int. F o r po i nte r-to -m e m b e r ty pe s, BaseT i s th e ty pe o f th e m e m be r, and ClassT i s th e cl ass to w h i ch th e m e m be r be l o ng s. F o r e x am pl e , i f T i s a po i nte r-to -m e m b e r f u ncti o n o f ty pe int(X::*)(), th e n BaseT i s th e f u ncti o n ty pe int(), and ClassT i s X. If T i s no t a po i nte r-to -m e m b e r ty pe , th e ClassT i s CompoundT<void> (an arbi trary ch o i ce ; y o u m i g h t pre f e r a no ncl ass).

P arti al spe ci al i z ati o ns f o r po i nte rs and re f e re nce s are f ai rl y strai g h tf o rw ard:

// types/type3.hpp template<typename T> class CompoundT<T&> { // partial specialization for references public: enum { IsPtrT = 0, IsRefT = 1, IsArrayT = 0, IsFuncT = 0, IsPtrMemT = 0 }; typedef T BaseT; typedef typename CompoundT<T>::BottomT BottomT; typedef CompoundT<void> ClassT; };

Page 405: CPlusPlus Templates The Complete Guide

template<typename T> class CompoundT<T*> { // partial specialization for pointers public: enum { IsPtrT = 1, IsRefT = 0, IsArrayT = 0, IsFuncT = 0, IsPtrMemT = 0 }; typedef T BaseT; typedef typename CompoundT<T>::BottomT BottomT; typedef CompoundT<void> ClassT; };

A rray s and po i nte rs to m e m be rs can be tre ate d u si ng th e sam e te ch ni q u e , bu t i t m ay co m e as a su rpri se th at th e parti al spe ci al i z ati o ns i nv o l v e m o re te m pl ate param e te rs th an th e pri m ary te m pl ate :

// types/type4.hpp #include <stddef.h> template<typename T, size_t N> class CompoundT <T[N]> { // partial specialization for arrays public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 1, IsFuncT = 0, IsPtrMemT = 0 }; typedef T BaseT; typedef typename CompoundT<T>::BottomT BottomT; typedef CompoundT<void> ClassT; }; template<typename T> class CompoundT <T[]> { // partial specialization for empty arrays public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 1, IsFuncT = 0, IsPtrMemT = 0 }; typedef T BaseT; typedef typename CompoundT<T>::BottomT BottomT; typedef CompoundT<void> ClassT; }; template<typename T, typename C> class CompoundT <T C::*> { // partial specialization for pointer-to-members public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 0, IsPtrMemT = 1 }; typedef T BaseT; typedef typename CompoundT<T>::BottomT BottomT; typedef C ClassT; };

T h e w atch f u l re ade r m ay h av e no te d th at th e de f i ni ti o n o f th e BottomT m e m b e r re q u i re s th e re cu rsi v e i nstanti ati o n o f th e CompoundT te m pl ate f o r v ari o u s ty pe s T. T h e re cu rsi o n e nds w h e n T i s no l o ng e r a co m po u nd ty pe ; h e nce th e g e ne ri c te m pl ate de f i ni ti o n i s u se d (o r w h e n T i s a f u ncti o n ty pe , as w e se e l ate r o n).

Page 406: CPlusPlus Templates The Complete Guide

F u ncti o n ty pe s are h arde r to re co g ni z e . In th e ne x t se cti o n w e u se f ai rl y adv ance d te m pl ate te ch ni q u e s to re co g ni z e f u ncti o n ty pe s.

Page 407: CPlusPlus Templates The Complete Guide

19.3 Identifying Function Types

T h e pro bl e m w i th f u ncti o n ty pe s i s th at be cau se o f th e arbi trary nu m be r o f param e te rs, th e re i sn' t a f i ni te sy ntacti c co nstru ct u si ng te m pl ate param e te rs th at de scri be s th e m al l . O ne appro ach to re so l v e th i s pro bl e m i s to pro v i de parti al spe ci al i z ati o ns f o r f u ncti o ns w i th a te m pl ate arg u m e nt l i st th at i s sh o rte r th an a ch o se n l i m i t. T h e f i rst f e w su ch parti al spe ci al i z ati o ns can be de f i ne d as f o l l o w s:

// types/type5.hpp template<typename R> class CompoundT<R()> { public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 1, IsPtrMemT = 0 }; typedef R BaseT(); typedef R BottomT(); typedef CompoundT<void> ClassT; }; template<typename R, typename P1> class CompoundT<R(P1)> { public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 1, IsPtrMemT = 0 }; typedef R BaseT(P1); typedef R BottomT(P1); typedef CompoundT<void> ClassT; }; template<typename R, typename P1> class CompoundT<R(P1, ...)> { public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 1, IsPtrMemT = 0 }; typedef R BaseT(P1); typedef R BottomT(P1); typedef CompoundT<void> ClassT; }; …

T h i s appro ach h as th e adv antag e th at w e can cre ate ty pe de f m e m b e rs f o r e ach param e te r ty pe .

A m o re g e ne ral te ch ni q u e u se s th e S F INA E (su bsti tu ti o n-f ai l u re -i s-no t-an-e rro r) pri nci pl e o f S e cti o n 8 .3 .1 o n pag e 1 0 6 : A n o v e rl o ade d f u ncti o n te m pl ate can be f o l l o w e d by e x pl i ci t te m pl ate arg u m e nts th at are i nv al i d f o r so m e o f th e te m pl ate s. T h i s can be co m bi ne d w i th th e appro ach u se d f o r th e cl assi f i cati o n o f e nu m e rati o n ty pe s u si ng o v e rl o ad re so l u ti o n. T h e k e y to e x pl o i t S F INA E i s to f i nd a ty pe co nstru ct th at i s i nv al i d f o r f u ncti o n ty pe s bu t no t f o r o th e r ty pe s, o r v i ce

Page 408: CPlusPlus Templates The Complete Guide

v e rsa. B e cau se w e are al re ady abl e to re co g ni z e v ari o u s ty pe cate g o ri e s, w e can al so e x cl u de th e m f ro m co nsi de rati o n. T h e re f o re , o ne co nstru ct th at i s u se f u l i s th e array ty pe . Its e l e m e nts canno t be void, re f e re nce s, o r f u ncti o ns. T h i s i nspi re s th e f o l l o w i ng co de :

template<typename T> class IsFunctionT { private: typedef char One; typedef struct { char a[2]; } Two; template<typename U> static One test(...); template<typename U> static Two test(U (*)[1]); public: enum { Yes = sizeof(IsFunctionT<T>::test<T>(0)) == 1 }; enum { No = !Yes }; };

W i th th i s te m pl ate de f i ni ti o n, IsFunctionT<T>::Yes i s no nz e ro o nl y f o r ty pe s th at canno t be ty pe s o f array e l e m e nts. T h e o nl y sh o rtco m i ng o f th i s o bse rv ati o n i s th at th i s i s no t o nl y th e case f o r f u ncti o n ty pe s, bu t i t i s al so th e case f o r re f e re nce ty pe s and f o r void ty pe s. F o rtu nate l y , th i s i s e asi l y re m e di e d by pro v i di ng parti al spe ci al i z ati o n f o r re f e re nce ty pe s and e x pl i ci t spe ci al i z ati o ns f o r void ty pe s:

template<typename T> class IsFunctionT<T&> { public: enum { Yes = 0 }; enum { No = !Yes }; }; template<> class IsFunctionT<void> { public: enum { Yes = 0 }; enum { No = !Yes }; }; template<> class IsFunctionT<void const> { public: enum { Yes = 0 }; enum { No = !Yes }; }; …

V ari o u s al te rnati v e s e x i st. F o r e x am pl e , a f u ncti o n ty pe F i s al so u ni q u e i n th at a re f e re nce F& i m pl i ci tl y co nv e rts to F* w i th o u t an u se r-de f i ne d co nv e rsi o n.

T h e se co nsi de rati o ns al l o w u s to re w ri te th e pri m ary CompoundT te m pl ate as

Page 409: CPlusPlus Templates The Complete Guide

f o l l o w s:

// types/type6.hpp template<typename T> class IsFunctionT { private: typedef char One; typedef struct { char a[2]; } Two; template<typename U> static One test(...); template<typename U> static Two test(U (*)[1]); public: enum { Yes = sizeof(IsFunctionT<T>::test<T>(0)) == 1 }; enum { No = !Yes }; }; template<typename T> class IsFunctionT<T&> { public: enum { Yes = 0 }; enum { No = !Yes }; }; template<> class IsFunctionT<void> { public: enum { Yes = 0 }; enum { No = !Yes }; }; template<> class IsFunctionT<void const> { public: enum { Yes = 0 }; enum { No = !Yes }; }; // same for void volatile and void const volatile … template<typename T> class CompoundT { // primary template public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = IsFunctionT<T>::Yes, IsPtrMemT = 0 }; typedef T BaseT; typedef T BottomT; typedef CompoundT<void> ClassT; };

T h i s i m pl e m e ntati o n o f th e pri m ary te m pl ate do e s no t e x cl u de th e spe ci al i z ati o ns pro po se d e arl i e r, so th at f o r a l i m i te d nu m be r o f param e te rs th e re tu rn ty pe s and th e param e te r ty pe s can be acce sse d.

A n i nte re sti ng h i sto ri cal al te rnati v e re l i e s o n th e f act th at at so m e ti m e i n th e

Page 410: CPlusPlus Templates The Complete Guide

h i sto ry o f C + + ,

template<class T> struct X { long aligner; Tm; };

co u l d de cl are a m e m be r f u ncti o n X::m() i nste ad o f a no nstati c data m e m b e r X::m (th i s i s no l o ng e r tru e i n standard C + + ). O n al l i m pl e m e ntati o ns o f th at ti m e , X<T> w o u l d no t be l arg e r th an th e f o l l o w i ng X0 ty pe w h e n T w as a f u ncti o n ty pe (be cau se no nv i rtu al m e m be r f u ncti o ns do n' t i ncre ase th e si z e o f a cl ass i n practi ce ):

struct X0 { long aligner; };

O n th e o th e r h and, X<T> w o u l d be l arg e r th an X0 i f T w e re an o bj e ct ty pe (th e m e m be r aligner w as re q u i re d be cau se , f o r e x am pl e , an e m pty cl ass ty pi cal l y h as th e sam e si z e as a cl ass w i th j u st a char m e m be r).

W i th al l th i s i n pl ace , w e can no w cl assi f y al l ty pe s, e x ce pt cl ass ty pe s and e nu m e rati o n ty pe s. If a ty pe i s no t a f u ndam e ntal ty pe and no t o ne o f th e ty pe s re co g ni z e d u si ng th e CompoundT te m pl ate , i t m u st be an e nu m e rati o n o r a cl ass ty pe . In th e f o l l o w i ng se cti o n, w e re l y o n o v e rl o ad re so l u ti o n to di sti ng u i sh be tw e e n th e tw o .

Page 411: CPlusPlus Templates The Complete Guide

19.4 Enumeration Classification with Overload Resolution

O v e rl o ad re so l u ti o n i s th e pro ce ss th at se l e cts am o ng v ari o u s f u ncti o ns w i th a sam e nam e base d o n th e ty pe s o f th e i r arg u m e nts. A s sh o w n sh o rtl y , w e can de te rm i ne th e o u tco m e o f a case o f o v e rl o ad re so l u ti o n w i th o u t actu al l y e v al u ati ng a f u ncti o n cal l . T h i s i s u se f u l to te st w h e th e r a parti cu l ar i m pl i ci t co nv e rsi o n e x i sts. T h e i m pl i ci t co nv e rsi o n th at i nte re sts u s parti cu l arl y i s th e co nv e rsi o n f ro m an e nu m e rati o n ty pe to an i nte g ral ty pe : It al l o w s u s to i de nti f y e nu m e rati o n ty pe s.

E x pl anati o ns f o l l o w th e co m pl e te i m pl e m e ntati o n o f th i s te ch ni q u e :

// types/type7.hpp struct SizeOverOne { char c[2]; }; template<typename T, bool convert_possible = !CompoundT<T>::IsFuncT && !CompoundT<T>::IsArrayT> class ConsumeUDC { public: operator T() const; }; // conversion to function types is not possible template <typename T> class ConsumeUDC<T, false> { }; // conversion to void type is not possible template <bool convert_possible> class ConsumeUDC<void, convert_possible> { }; char enum_check(bool); char enum_check(char); char enum_check(signed char); char enum_check(unsigned char); char enum_check(wchar_t); char enum_check(signed short); char enum_check(unsigned short); char enum_check(signed int); char enum_check(unsigned int); char enum_check(signed long); char enum_check(unsigned long); #if LONGLONG_EXISTS char enum_check(signed long long); char enum_check(unsigned long long); #endif // LONGLONG_EXISTS // avoid accidental conversions from float to int

Page 412: CPlusPlus Templates The Complete Guide

char enum_check(float); char enum_check(double); char enum_check(long double); SizeOverOne enum_check(...); // catch all template<typename T> class IsEnumT { public: enum { Yes = IsFundaT<T>::No && !CompoundT<T>::IsRefT && !CompoundT<T>::IsPtrT && !CompoundT<T>::IsPtrMemT && sizeof(enum_check(ConsumeUDC<T>()))==1 }; enum { No = !Yes }; };

A t th e h e art o f o u r de v i ce i s a sizeof e x pre ssi o n appl i e d to a f u ncti o n cal l . It re su l ts i n th e si z e o f th e re tu rn ty pe o f th e se l e cte d f u ncti o n. H e nce , o v e rl o ad se l e cti o n ru l e s are appl i e d to re so l v e th e cal l to enum_check() , bu t no de f i ni ti o n o f th e f u ncti o n i s ne e de d be cau se th e f u ncti o n i s no t actu al l y cal l e d. In th i s case , enum_check() re tu rns a char, w h i ch h as si z e 1 i f th e arg u m e nt i s co nv e rti bl e to an i nte g ral ty pe . A l l o th e r ty pe s are co v e re d by an e l l i psi s f u ncti o n, bu t passi ng an arg u m e nt " by e l l i psi s" i s th e l e ast de si rabl e f ro m an o v e rl o ad re so l u ti o n po i nt o f v i e w . T h e re tu rn ty pe o f th e e l l i psi s v e rsi o n o f enum_check() w as cre ate d spe ci f i cal l y to e nsu re i t h as a si z e l arg e r th an o ne by te . [1]

[1] A ty pe l i k e double w o u l d al m o st su re l y w o rk i n practi ce , bu t i n th e o ry su ch a ty pe m ay h av e si z e " o ne by te ." A n array ty pe canno t be u se d as a re tu rn ty pe , so w e e ncapsu l ate d o ne i n a stru ctu re .

T h e arg u m e nt f o r th e cal l to enum_check() m u st be cre ate d care f u l l y . F i rst, no te th at w e do n' t actu al l y k no w h o w a T can be co nstru cte d. P e rh aps a spe ci al co nstru cto r m u st be cal l e d? T o re so l v e th i s pro bl e m , w e can de cl are a f u ncti o n th at re tu rns a T and cre ate an arg u m e nt by cal l i ng th at f u ncti o n i nste ad. B e cau se w e are i n a sizeof e x pre ssi o n, w e do n' t actu al l y ne e d to de f i ne th e f u ncti o n. P e rh aps m o re su btl e i s th e f act th at o v e rl o ad re so l u ti o n co u l d se l e ct an enum_check() de cl arati o n f o r an i nte g ral ty pe i f th e arg u m e nt h as a cl ass ty pe T, bu t th at cl ass ty pe de f i ne s a us e r -de f i ne d c onv e r s i on (so m e ti m e s al so cal l e d U D C ) f u ncti o n to an i nte g ral ty pe . T h i s pro bl e m i s so l v e d by actu al l y f o rci ng a u se r-de f i ne d co nv e rsi o n to T u si ng th e ConsumeUDC te m pl ate . T h e co nv e rsi o n o pe rato r al so tak e s care o f cre ati ng th e arg u m e nt o f ty pe T. T h e e x pre ssi o n f o r th e cal l to enum_check() i s th u s anal y z e d as f o l l o w s (se e A ppe ndi x B f o r a de tai l e d o v e rv i e w o f o v e rl o ad re so l u ti o n):

• T h e o ri g i nal arg u m e nt i s a te m po rary ConsumeUDC<T> o bj e ct. • If T i s a f u ndam e ntal i nte g ral ty pe , th e co nv e rsi o n o pe rato r i s re l i e d o n to

cre ate a m atch w i th an enum_check() th at tak e s ty pe T as i ts se co nd arg u m e nt.

Page 413: CPlusPlus Templates The Complete Guide

• If T i s an e nu m e rati o n ty pe , th e co nv e rsi o n o pe rato r i s re l i e d o n to e nabl e co nv e rsi o n to T , and ty pe pro m o ti o n i s i nv o k e d to m atch an enum_check() th at tak e s an i nte g ral ty pe (ty pi cal l y , enum_check(int,int)).

• If T i s a cl ass ty pe w i th a co nv e rsi o n o pe rato r to an i nte g ral ty pe , th e co nv e rsi o n o pe rato r canno t be co nsi de re d be cau se o nl y o ne u se r-de f i ne d co nv e rsi o n can be i nv o k e d f o r a m atch and w e w o u l d f i rst h av e to u se ano th e r su ch co nv e rsi o n f ro m ConsumeUDC<T> to T.

• No o th e r ty pe T co u l d be m ade to m atch an i nte g ral ty pe , so th e e l l i psi s v e rsi o n o f enum_check() i s se l e cte d.

F i nal l y , be cau se w e w ant to i de nti f y o nl y e nu m e rati o n ty pe s and no t f u ndam e ntal o r po i nte r ty pe s, w e u se th e IsFundaT and CompoundT ty pe s de v e l o pe d e arl i e r to e x cl u de th o se f ro m th e se t o f ty pe s th at cau se IsEnumT<T>::Yes to be no nz e ro .

Page 414: CPlusPlus Templates The Complete Guide

19.5 Determining Class Types

W i th al l th e cl assi f i cati o n te m pl ate s de scri be d i n th e pre v i o u s se cti o n, o nl y cl ass ty pe s (classe s, structs, and unions) re m ai n to be re co g ni z e d. O ne appro ach i s to u se th e S F INA E pri nci pl e as de m o nstrate d i n S e cti o n 1 5 .2 .2 o n pag e 2 6 6 .

A no th e r appro ach i s to pro ce e d by e l i m i nati o n: If a ty pe i s no t a f u ndam e ntal ty pe , no t an e nu m e rati o n ty pe , and no t a co m po u nd ty pe , i t m u st be a cl ass ty pe . T h e f o l l o w i ng strai g h tf o rw ard te m pl ate i m pl e m e nts th i s i de a:

// types/type8.hpp template<typename T> class IsClassT { public: enum { Yes = IsFundaT<T>::No && IsEnumT<T>::No && !CompoundT<T>::IsPtrT && !CompoundT<T>::IsRefT && !CompoundT<T>::IsArrayT && !CompoundT<T>::IsPtrMemT && !CompoundT<T>::IsFuncT }; enum { No = !Yes }; };

Page 415: CPlusPlus Templates The Complete Guide

19.6 Putting It All Together

No w th at w e are abl e to cl assi f y any ty pe acco rdi ng to i ts k i nd, i t i s co nv e ni e nt to g ro u p al l th e cl assi f y i ng te m pl ate s i n a si ng l e g e ne ral -pu rpo se te m pl ate . T h e f o l l o w i ng re l ati v e l y sm al l h e ade r f i l e do e s j u st th at:

// types/typet.hpp #ifndef TYPET_HPP #define TYPET_HPP // define IsFundaT<> #include "type1.hpp" // define primary template CompoundT<> (first version) //#include "type2.hpp" // define primary template CompoundT<> (second version) #include "type6.hpp" // define CompoundT<> specializations #include "type3.hpp" #include "type4.hpp" #include "type5.hpp" // define IsEnumT<> #include "type7.hpp" // define IsClassT<> #include "type8.hpp" // define template that handles all in one style template <typename T> class TypeT { public: enum { IsFundaT = IsFundaT<T>::Yes, IsPtrT = CompoundT<T>::IsPtrT, IsRefT = CompoundT<T>::IsRefT, IsArrayT = CompoundT<T>::IsArrayT, IsFuncT = CompoundT<T>::IsFuncT, IsPtrMemT = CompoundT<T>::IsPtrMemT, IsEnumT = IsEnumT<T>::Yes, IsClassT = IsClassT<T>::Yes }; }; #endif // TYPET_HPP

T h e f o l l o w i ng pro g ram sh o w s an appl i cati o n o f al l th e se cl assi f i cati o n te m pl ate s:

// types/types.cpp #include "typet.hpp" #include <iostream>

Page 416: CPlusPlus Templates The Complete Guide

class MyClass { }; void myfunc() { } enum E { e1 }; // check by passing type as template argument template <typename T> void check() { if (TypeT<T>::IsFundaT) { std::cout << " IsFundaT "; } if (TypeT<T>::IsPtrT) { std::cout << " IsPtrT "; } if (TypeT<T>::IsRefT) { std::cout << " IsRefT "; } if (TypeT<T>::IsArrayT) { std::cout << " IsArrayT "; } if (TypeT<T>::IsFuncT) { std::cout << " IsFuncT "; } if (TypeT<T>::IsPtrMemT) { std::cout << " IsPtrMemT "; } if (TypeT<T>::IsEnumT) { std::cout << " IsEnumT "; } if (TypeT<T>::IsClassT) { std::cout << " IsClassT "; } std::cout << std::endl; } // check by passing type as function call argument template <typename T> void checkT (T) { check<T>(); // for pointer types check type of what they refer to if (TypeT<T>::IsPtrT || TypeT<T>::IsPtrMemT) { check<typename CompoundT<T>::BaseT>(); } } int main() { std::cout << "int:" << std::endl; check<int>(); std::cout << "int&:" << std::endl; check<int&>();

Page 417: CPlusPlus Templates The Complete Guide

std::cout << "char[42]:" << std::endl; check<char[42]>(); std::cout << "MyClass:" << std::endl; check<MyClass>(); std::cout << "ptr to enum:" << std::endl; E* ptr = 0; checkT(ptr); std::cout << "42:" << std::endl; checkT(42); std::cout << "myfunc():" << std::endl; checkT(myfunc); std::cout << "memptr to array:" << std::endl; char (MyClass::* memptr) [] = 0; checkT(memptr); }

T h e pro g ram h as th e f o l l o w i ng o u tpu t:

int: IsFundaT int&: IsRefT char[42]: IsArrayT MyClass: IsClassT ptr to enum: IsPtrT IsEnumT 42: IsFundaT myfunc(): IsPtrT IsFuncT memptr to array: IsPtrMemT IsArrayT

Page 418: CPlusPlus Templates The Complete Guide

19.7 Afternotes

T h e abi l i ty f o r a pro g ram to i nspe ct i ts o w n h i g h -l e v e l pro pe rti e s (su ch as i ts ty pe stru ctu re s) i s so m e ti m e s cal l e d r e f l e c t i on. O u r f ram e w o rk th e re f o re i m pl e m e nts a f o rm o f c om p i l e -t i m e r e f l e c t i on , w h i ch tu rns o u t to be a po w e rf u l al l y to m e t a p r og r a m m i ng (se e C h apte r 1 7 ).

T h e i de a o f sto ri ng pro pe rti e s o f ty pe s as m e m be rs o f te m pl ate spe ci al i z ati o ns date s back to at l e ast th e m i d-1 9 9 0 s. A m o ng th e e arl i e r se ri o u s appl i cati o ns o f ty pe cl assi f i cati o n te m pl ate s w as th e __type_traits u ti l i ty i n th e S T L i m pl e m e ntati o n di stri bu te d by S G I (th e n k no w n as S i l i c on G r a p h i c s ). T h e S G I te m pl ate w as m e ant to re pre se nt so m e pro pe rti e s o f i ts te m pl ate arg u m e nt (f o r e x am pl e , w h e th e r i t w as a P O D ty pe o r w h e th e r i ts de stru cto r w as tri v i al ). T h i s i nf o rm ati o n w as th e n u se d to o pti m i z e ce rtai n S T L al g o ri th m s f o r th e g i v e n ty pe . A n i nte re sti ng f e atu re o f th e S G I so l u ti o n w as th at so m e S G I co m pi l e rs re co g ni z e d th e __type_traits spe ci al i z ati o ns and pro v i de d i nf o rm ati o n abo u t th e arg u m e nts th at co u l d no t be de ri v e d u si ng standard te ch ni q u e s. (T h e g e ne ri c i m pl e m e ntati o n o f th e __type_traits te m pl ate w as saf e to u se , al be i t su bo pti m al .)

T h e u se o f th e S F INA E pri nci pl e f o r ty pe cl assi f i cati o n pu rpo se s h ad be e n no te d w h e n th e S F INA E pri nci pl e w as cl ari f i e d du ri ng th e standardi z ati o n e f f o rt. H o w e v e r, i t w as ne v e r f o rm al l y do cu m e nte d, and as a re su l t m u ch e f f o rt w as l ate r spe nt try i ng to re cre ate so m e o f th e te ch ni q u e s de scri be d i n th i s ch apte r. O ne o f th e no tabl e e arl y co ntri bu ti o ns w as by A ndre i A l e x andre scu w h o m ade po pu l ar th e u se o f th e sizeof o pe rato r to de te rm i ne th e o u tco m e o f o v e rl o ad re so l u ti o n.

F i nal l y , w e sh o u l d no te th at a rath e r co m pl e te ty pe cl assi f i cati o n te m pl ate h as be e n i nco rpo rate d i n th e B o o st l i brary (se e [B o o stT y pe T rai ts]). In tu rn, th i s i m pl e m e ntati o n i s th e basi s o f an e f f o rt to add su ch a f aci l i ty to th e standard l i brary . S e e al so S e cti o n 1 3 .1 0 o n pag e 2 1 8 f o r a re l ate d l ang u ag e e x te nsi o n.

Page 419: CPlusPlus Templates The Complete Guide

Chapter 20. Smart Pointers

M e m o ry i s a re so u rce th at i s no rm al l y e x pl i ci tl y m anag e d i n C + + pro g ram s. T h i s m anag e m e nt i nv o l v e s th e acq u i si ti o n and di spo sal o f bl o ck s o f raw m e m o ry .

O ne o f th e m o re de l i cate i ssu e s i n m anag i ng dy nam i cal l y al l o cate d m e m o ry i s th e de ci si o n o f w h e n to de al l o cate i t. A m o ng th e v ari o u s to o l s to si m pl i f y th i s aspe ct o f pro g ram m i ng are so -cal l e d s m a r t p oi nt e r te m pl ate s. In C + + , sm art po i nte rs are cl asse s th at be h av e so m e w h at l i k e o rdi nary po i nte rs (i n th at th e y pro v i de th e de re f e re nci ng o pe rato rs -> and *) bu t i n addi ti o n e ncapsu l ate so m e m e m o ry o r re so u rce m anag e m e nt po l i cy .

In th i s ch apte r w e de v e l o p sm art po i nte r te m pl ate s th at e ncapsu l ate tw o di f f e re nt ow ne r s h i p m o de l s—e x cl u si v e and sh are d:

• E x cl u si v e o w ne rsh i p can be e nf o rce d w i th l i ttl e o v e rh e ad, co m pare d w i th h andl i ng raw po i nte rs. S m art po i nte rs th at e nf o rce su ch a po l i cy are u se f u l to de al w i th e x ce pti o ns th ro w n w h i l e m ani pu l ati ng dy nam i cal l y al l o cate d o bj e cts.

• S h are d o w ne rsh i p can so m e ti m e s l e ad to e x ce ssi v e l y co m pl i cate d o bj e ct l i f e ti m e si tu ati o ns. In su ch case s, i t m ay be adv i sabl e to m o v e th e bu rde n o f th e l i f e ti m e de ci si o ns f ro m th e pro g ram m e r to th e pro g ram .

T h e te rm s m a r t p oi nt e r i m pl i e s th at ob j e c t s are be i ng po i nte d to . A l te rnati v e s f o r f unc t i on po i nte rs are su bj e ct to di f f e re nt i ssu e s, so m e o f w h i ch are di scu sse d i n C h apte r 2 2 .

Page 420: CPlusPlus Templates The Complete Guide

20.1 Holders and Trules

T h i s se cti o n i ntro du ce s tw o sm art po i nte r ty pe s: a h ol de r ty pe to h o l d an o bj e ct e x cl u si v e l y and a so -cal l e d t r ul e to e nabl e th e transf e r o f o w ne rsh i p f ro m o ne h o l de r to ano th e r.

20.1.1 Protecting Against Exceptions

E x ce pti o ns w e re i ntro du ce d i n C + + to i m pro v e th e re l i abi l i ty o f C + + pro g ram s. T h e y al l o w re g u l ar and e x ce pti o nal e x e cu ti o n path s to be m o re cl e anl y se parate d. Y e t sh o rtl y af te r e x ce pti o ns w e re i ntro du ce d, v ari o u s C + + pro g ram m i ng au th o rs and co l u m ni sts starte d o bse rv i ng th at a nai v e u se o f e x ce pti o ns l e ads to tro u bl e , and parti cu l arl y to m e m o ry l e ak s. T h e f o l l o w i ng e x am pl e sh o w s bu t o ne o f th e m any tro u bl e so m e si tu ati o ns th at co u l d ari se :

void do_something() { Something* ptr = new Something; // perform some computation with *ptr ptr->perform(); … delete ptr; }

T h i s f u ncti o n cre ate s an o bj e ct w i th new, pe rf o rm s so m e o pe rati o ns w i th th i s o bj e ct, and de stro y s th e o bj e ct at th e e nd o f th e f u ncti o n w i th delete. U nf o rtu nate l y , i f so m e th i ng g o e s w ro ng af te r th e cre ati o n bu t be f o re th e de l e ti o n o f th e o bj e ct and an e x ce pti o n g e ts th ro w n, th e o bj e ct i s no t de al l o cate d and th e pro g ram l e ak s m e m o ry . O th e r pro bl e m s m ay ari se be cau se th e de stru cto r i s no t cal l e d (f o r e x am pl e , bu f f e rs m ay no t be w ri tte n o u t to di sk , ne tw o rk co nne cti o ns m ay no t be re l e ase d, o n-scre e n w i ndo w s m ay no t be cl o se d, and so f o rth ). T h i s parti cu l ar case can be h andl e d f ai rl y e asi l y u si ng an e x pl i ci t e x ce pti o n h andl e r:

void do_something() { Something* ptr = 0; try { ptr = new Something; // perform some computation with *ptr ptr->perform(); … } catch (...) { delete ptr;

Page 421: CPlusPlus Templates The Complete Guide

throw; // rethrow the exception that was caught } return result; }

T h i s i s m anag e abl e , bu t al re ady w e f i nd th at th e e x ce pti o nal path i s starti ng to do m i nate th e re g u l ar path , and th e de l e ti o n o f th e o bj e ct h as to be do ne i n tw o di f f e re nt pl ace s: o nce i n th e re g u l ar path and o nce i n th e e x ce pti o nal path . T h i s av e nu e q u i ck l y g ro w s w o rse . C o nsi de r w h at h appe ns i f w e ne e d to cre ate tw o o bj e cts i n a si ng l e f u ncti o n:

void do_two_things() { Something* first = new Something; first->perform(); Something* second = new Something; second->perform(); delete second; delete first; }

U si ng an e x pl i ci t e x ce pti o n h andl e r, th e re are v ari o u s w ay s to m ak e th i s e x ce pti o n-saf e , bu t no ne se e m s v e ry appe al i ng . H e re i s o ne o pti o n:

void do_two_things() { Something* first = 0; Something* second = 0; try { first = new Something; first->perform(); second = new Something; second->perform(); } catch (...) { delete first; delete second; throw; // rethrow the exception that was caught } delete second; delete first; }

H e re w e m ade th e assu m pti o n th at th e delete o pe rati o ns w i l l no t th e m se l v e s tri g g e r e x ce pti o ns. [1] In th i s e x am pl e , th e e x ce pti o n h andl i ng co de i s a v e ry l arg e part o f th e ro u ti ne , bu t m o re i m po rtant, i t co u l d be arg u e d th at i t i s th e m o st su btl e part o f i t. T h e ne e d f o r e x ce pti o n saf e ty h as al so si g ni f i cantl y ch ang e d th e stru ctu re o f th e re g u l ar path o f o u r ro u ti ne —pe rh aps m o re so th an y o u m ay f e e l co m f o rtabl e w i th .

Page 422: CPlusPlus Templates The Complete Guide

[1] T h i s i s a re aso nabl e assu m pti o n. D e stru cto rs th at th ro w e x ce pti o ns sh o u l d g e ne ral l y be av o i de d be cau se de stru cto rs are au to m ati cal l y cal l e d w h e n an e x ce pti o n i s th ro w n, and th ro w i ng ano th e r e x ce pti o n w h i l e th i s h appe ns re su l ts i n i m m e di ate pro g ram te rm i nati o n.

20.1.2 Holders

F o rtu nate l y , i t i s no t v e ry h ard to w ri te a sm al l cl ass te m pl ate th at e sse nti al l y e ncapsu l ate s th e po l i cy i n th e se co nd e x am pl e . T h e i de a i s to w ri te a cl ass th at be h av e s m o st l i k e a po i nte r, bu t w h i ch de stro y s th e o bj e ct to w h i ch i t po i nts i f i t i s i tse l f de stro y e d o r i f ano th e r po i nte r i s assi g ne d to i t. S u ch a cl ass co u l d be cal l e d a h ol de r be cau se i t i s m e ant to h o l d an o bj e ct saf e l y w h i l e w e pe rf o rm v ari o u s co m pu tati o ns. H e re i s h o w w e co u l d do th i s:

// pointers/holder.hpp template <typename T> class Holder { private: T* ptr; // refers to the object it holds (if any) public: // default constructor: let the holder refer to nothing Holder() : ptr(0) { } // constructor for a pointer: let the holder refer to where the pointer refers explicit Holder (T* p) : ptr(p) { } // destructor: releases the object to which it refers (if any) ~Holder() { delete ptr; } // assignment of new pointer Holder<T>& operator= (T* p) { delete ptr; ptr = p; return *this; } // pointer operators T& operator* () const { return *ptr; } T* operator-> () const { return ptr; } // get referenced object (if any) T* get() const { return ptr; }

Page 423: CPlusPlus Templates The Complete Guide

// release ownership of referenced object void release() { ptr = 0; } // exchange ownership with other holder void exchange_with (Holder<T>& h) { swap(ptr,h.ptr); } // exchange ownership with other pointer void exchange_with (T*& p) { swap(ptr,p); } private: // no copying and copy assignment allowed Holder (Holder<T> const&); Holder<T>& operator= (Holder<T> const&); };

S e m anti cal l y , th e h o l de r tak e s o w ne rsh i p o f th e o bj e ct to w h i ch ptr re f e rs. T h i s o bj e ct h as to be cre ate d w i th new, be cau se delete i s u se d w h e ne v e r th e o bj e ct o w ne d by th e h o l de r h as to be de stro y e d. [2 ] T h e release() m e m be r re m o v e s co ntro l o v e r th e h e l d o bj e ct f ro m th e h o l de r. H o w e v e r, th e pl ai n assi g nm e nt o pe rato r i s sm art e no u g h to de stro y and de al l o cate any o bj e ct h e l d be cau se ano th e r o bj e ct w i l l be h e l d i nste ad and th e assi g nm e nt o pe rato r do e s no t re tu rn a h o l de r o r po i nte r f o r th e o ri g i nal o bj e ct. W e adde d tw o exchange_with() m e m be rs th at al l o w u s to re pl ace co nv e ni e ntl y th e o bj e ct be i ng h e l d w i th o u t de stro y i ng i t.

[2 ] A te m pl ate param e te r de f i ni ng a de al l o cati o n po l i cy co u l d be adde d to i m pro v e f l e x i bi l i ty i n th i s are a.

O u r e x am pl e w i th tw o al l o cati o ns can be re w ri tte n as f o l l o w s:

void do_two_things() { Holder<Something> first(new Something); first->perform(); Holder<Something> second(new Something); second->perform(); }

T h i s i s m u ch cl e ane r. No t o nl y i s th e co de e x ce pti o n-saf e be cau se o f th e w o rk do ne by th e Holder de stru cto rs, bu t th e de l e ti o n i s al so au to m ati cal l y do ne w h e n th e f u ncti o n te rm i nate s th ro u g h i ts re g u l ar path (at w h i ch po i nt th e o bj e cts i nde e d w e re to be de stro y e d).

Page 424: CPlusPlus Templates The Complete Guide

No te th at y o u can' t u se th e assi g nm e nt-l i k e sy ntax f o r i ni ti al i z ati o n:

Holder<Something> first = new Something; // ERROR

T h i s i s be cau se th e co nstru cto r i s de cl are d as explicit and th e re i s a m i no r di f f e re nce be tw e e n

X x; Y y(x); // explicit conversion

and

X x; Y y = x; // implicit conversion

T h e f o rm e r cre ate s a ne w o bj e ct o f ty pe Y by u si ng an e x pl i ci t co nv e rsi o n f ro m ty pe X, w h e re as th e l atte r cre ate s a ne w o bj e ct o f ty pe Y by u si ng an i m pl i ci t co nv e rsi o n, bu t i n o u r case i m pl i ci t co nv e rsi o ns are i nh i bi te d by th e k e y w o rd explicit.

20.1.3 Holders as Members

W e can al so av o i d re so u rce l e ak s by u si ng h o l de rs w i th i n a cl ass. W h e n a m e m b e r h as a h o l de r ty pe i nste ad o f an o rdi nary po i nte r ty pe , w e o f te n no l o ng e r ne e d to de al e x pl i ci tl y w i th th at m e m be r i n th e de stru cto r be cau se th e o bj e ct to w h i ch i t re f e rs g e ts de l e te d w i th th e de l e ti o n o f th e h o l de r m e m b e r. In addi ti o n, a h o l de r h e l ps to av o i d re so u rce l e ak s th at are cau se d by e x ce pti o ns th at are th ro w n du ri ng th e i ni ti al i z ati o n o f an o bj e ct. No te th at de stru cto rs are cal l e d o nl y f o r th o se o bj e cts th at are co m pl e te l y co nstru cte d. S o , i f an e x ce pti o n o ccu rs i nsi de a co nstru cto r, de stru cto rs are cal l e d o nl y f o r m e m be r o bj e cts w i th a co nstru cto r th at f i ni sh e d no rm al l y . W i th o u t h o l de rs, th i s m ay re su l t i n a re so u rce l e ak i f , f o r e x am pl e , a f i rst su cce ssf u l al l o cati o n w as f o l l o w e d by an u nsu cce ssf u l o ne . F o r e x am pl e :

// pointers/refmem1.hpp class RefMembers { private: MemType* ptr1; // referenced members MemType* ptr2; public: // default constructor // - will cause resource leak if second new throws RefMembers () : ptr1(new MemType), ptr2(new MemType) { }

Page 425: CPlusPlus Templates The Complete Guide

// copy constructor // - might cause resource leak if second new throws RefMembers (RefMembers const& x) : ptr1(new MemType(*x.ptr1)), ptr2(new MemType(*x.ptr2)) { } // assignment operator const RefMembers& operator= (RefMembers const& x) { *ptr1 = *x.ptr1; *ptr2 = *x.ptr2; return *this; } ~RefMembers () { delete ptr1; delete ptr2; } … };

B y u si ng h o l de rs i nste ad o f o rdi nary po i nte r m e m be rs, w e e asi l y av o i d th e se po te nti al re so u rce l e ak s:

// pointers/refmem2.hpp #include "holder.hpp" class RefMembers { private: Holder<MemType> ptr1; // referenced members Holder<MemType> ptr2; public: // default constructor // - no resource leak possible RefMembers () : ptr1(new MemType), ptr2(new MemType) { } // copy constructor // - no resource leak possible RefMembers (RefMembers const& x) : ptr1(new MemType(*x.ptr1)), ptr2(new MemType(*x.ptr2)) { } // assignment operator const RefMembers& operator= (RefMembers const& x) { *ptr1 = *x.ptr1; *ptr2 = *x.ptr2; return *this; } // no destructor necessary // (default destructor lets ptr1 and ptr2 delete their objects) … };

No te th at al th o u g h w e can no w o m i t a u se r-de f i ne d de stru cto r, w e sti l l h av e to

Page 426: CPlusPlus Templates The Complete Guide

pro g ram th e co py co nstru cto r and th e assi g nm e nt o pe rato r.

20.1.4 Resource Acquisition Is Initialization

T h e g e ne ral i de a su ppo rte d by h o l de rs i s a patte rn cal l e d r e s our c e a c q ui s i t i on i s i ni t i a l i z a t i on o r j u st R A I I , w h i ch w as i ntro du ce d i n [S tro u stru pD nE ]. B y i ntro du ci ng te m pl ate param e te rs f o r de al l o cati o n po l i ci e s, w e can re pl ace al l co de th at m atch e s th e f o l l o w i ng o u tl i ne :

void do() { // acquire resources RES1* res1 = acquire_resource_1(); RES2* res2 = acquire_resource_2(); … // release resources release_resource_2(res); release_resource_1(res); }

w i th

void do() { // acquire resources Holder<RES1,… > res1(acquire_resource_1()); Holder<RES2,… > res2(acquire_resource_2()); … }

T h i s can be do ne by so m e th i ng si m i l ar to o u r u se s o f Holder , w i th th e adde d adv antag e th at th e co de i s e x ce pti o n-saf e .

20.1.5 Holder Limitations

No t e v e ry pro bl e m i s re so l v e d w i th o u r i m pl e m e ntati o n o f th e Holder te m pl ate . C o nsi de r th e f o l l o w i ng e x am pl e :

Something* load_something() { Something* result = new Something; read_something(result); return result; }

In th i s e x am pl e , tw o th i ng s m ak e th e co de m o re co m pl i cate d:

1. I n s i d e t h e f u n c t i o n , read_something() , w h i c h i s a f u n c t i o n t h a t e x p e c t s a n o r d i n a r y p o i n t e r a s i t s

Page 427: CPlusPlus Templates The Complete Guide

a r g u m e n t , i s c a l l e d . 2 . load_something() r e t u r n s a n o r d i n a r y p o i n t e r .

No w , u si ng a h o l de r, th e co de be co m e s e x ce pti o n-saf e bu t m o re co m pl i cate d:

Something* load_something() { Holder<Something> result(new Something); read_something(result.get_pointer()); Something* ret = result.get_pointer(); result.release(); return ret; }

P re su m abl y , th e f u ncti o n read_something() i s no t aw are o f th e Holder ty pe ; h e nce w e m u st e x tract th e re al po i nte r u si ng th e m e m b e r f u ncti o n get_pointer(). B y u si ng th i s m e m b e r f u ncti o n, th e h o l de r k e e ps co ntro l o v e r th e o bj e ct, and th e re ci pi e nt o f th e re su l t o f th e f u ncti o n cal l sh o u l d u nde rstand th at i t do e s no t o w n th e o bj e ct w h o se po i nte r i t g e ts—th e h o l de r do e s.

If no get_pointer() m e m be r f u ncti o n i s pro v i de d, w e can al so u se th e u se r-de f i ne d i ndi re cti o n o pe rato r * , f o l l o w e d by th e bu i l t-i n addre ss-o f o pe rato r &. Y e t ano th e r al te rnati v e i s to cal l o pe rato r -> e x pl i ci tl y . T h e f o l l o w i ng e x am pl e i l l u strate s th i s:

read_something(&*result); read_something(result.operator->());

Y o u ' l l pro babl y ag re e th at th e l atte r i s a parti cu l arl y u g l y al te rnati v e . H o w e v e r, i t m ay be appro pri ate to attract th e atte nti o n to th e f act th at so m e th i ng re l ati v e l y dang e ro u s i s be i ng do ne .

A no th e r i ssu e i n th e e x am pl e co de i s th at w e m u st cal l release() to cance l th e o w ne rsh i p o f th e o bj e ct be i ng re f e rre d to . T h i s pre v e nts th at o bj e ct f ro m be i ng de stro y e d w h e n th e f u ncti o n i s do ne ; h e nce i t can be re tu rne d to th e cal l e r. No te th at w e m u st sto re th e re tu rn v al u e i n a te m po rary v ari abl e be f o re re l e asi ng i t:

Something* ret = result.get_pointer(); result.release(); return ret;

T o av o i d th i s, w e can e nabl e state m e nts su ch as

return result,release();

Page 428: CPlusPlus Templates The Complete Guide

by m o di f y i ng release() so th at i t re tu rns th e o bj e ct pre v i o u sl y o w ne d:

template <typename T> class Holder { … T* release() { T* ret = ptr; ptr = 0; return ret; } … };

T h i s l e ads to an i m po rtant o bse rv ati o n: S m art po i nte rs are no t t h a t sm art, bu t u se d w i th a si m pl e co nsi ste nt po l i cy th e y do m ak e l i f e m u ch si m pl e r.

20.1.6 Copying Holders

Y o u pro babl y no ti ce d th at i n o u r i m pl e m e ntati o n o f th e Holder te m pl ate w e di sabl e d co py i ng o f h o l de rs by m ak i ng th e co py co nstru cto r and th e co py -assi g nm e nt o pe rato r pri v ate . Inde e d, th e pu rpo se o f co py i ng i s u su al l y to o btai n a se co nd o bj e ct th at i s e sse nti al l y i de nti cal to th e o ri g i nal . F o r a h o l de r th i s w o u l d m e an th at th e co py al so th i nk s i t co ntro l s w h e n th e o bj e ct g e ts de al l o cate d, and ch ao s e nsu e s be cau se bo th h o l de rs are i ncl i ne d to de al l o cate th e co ntro l l e d o bj e ct. T h u s, co py i ng i s no t an appro pri ate o pe rati o n f o r h o l de rs. Inste ad, w e can co nce i v e o f t r a ns f e r as be i ng th e natu ral co u nte rpart o f co py i ng i n th i s case .

A transf e r o pe rati o n i s f ai rl y e asi l y ach i e v e d u si ng a re l e ase o pe rati o n f o l l o w e d by i ni ti al i z ati o n o r assi g nm e nt, as sh o w n i n th e f o l l o w i ng :

Holder<Something> h1(new Something); Holder<Something> h2(h1.release());

No te ag ai n th at th e sy ntax

Holder<X> h = p;

w i l l no t w o rk be cau se i t i m pl i e s an i m pl i ci t co nv e rsi o n w h e re as th e co nstru cto r i s de cl are d as explicit:

Holder<Something> h2 = h1.release(); // ERROR

20.1.7 Copying Holders Across Function Calls

T h e e x pl i ci t transf e r w o rk s w e l l , bu t th e si tu ati o n i s a l i ttl e m o re su btl e w h e n th e

Page 429: CPlusPlus Templates The Complete Guide

transf e r i s acro ss a f u ncti o n cal l . F o r th e case o f passi ng a h o l de r f ro m a cal l e r to a cal l e e , w e can al w ay s pass by re f e re nce i nste ad o f passi ng by v al u e . U si ng th e " re l e ase f o l l o w e d by i ni ti al i z ati o n" appro ach can l e ad to pro bl e m s w h e n m o re th an o ne arg u m e nt i s passe d:

MyClass x; callee(h1.release(),x); // passing x may throw!

If th e co m pi l e r ch o o se s f i rst to cau se h1.release() to be e v al u ate d, th e n th e su bse q u e nt co py i ng o f x (assu m i ng i t i s passe d by v al u e ) m ay tri g g e r an e x ce pti o n th at o ccu rs, w h e re as no co m po ne nt i s i n ch arg e o f re l e asi ng th e o bj e ct th at u se d to be o w ne d by h o l de r h1. H e nce , a h o l de r sh o u l d al w ay s be passe d by re f e re nce .

U nf o rtu nate l y , i t i s i n g e ne ral no t co nv e ni e nt to r e t ur n a h o l de r by re f e re nce be cau se th i s re q u i re s th e h o l de r to h av e a l i f e ti m e th at e x ce e ds th e f u ncti o n cal l , w h i ch i n tu rn m ak e s i t u ncl e ar w h e n and h o w th e h o l de r w i l l de al l o cate th e o bj e ct u nde r i ts co ntro l . Y o u can bu i l d an arg u m e nt th at i t i s f i ne to cal l release() o n a h o l de r j u st pri o r to re tu rni ng th e e ncapsu l ate d po i nte r. T h i s i s e sse nti al l y w h at w e di d w i th load_something() e arl i e r. C o nsi de r th e f o l l o w i ng si tu ati o n:

Something* creator() { Holder<Something> h(new Something); MyClass x; // for illustration purposes return h.release(); }

W e m u st be aw are h e re th at th e de stru cti o n o f x co u l d cau se an e x ce pti o n to be th ro w n af te r h h as re l e ase d th e o bj e ct i t o w ne d and be f o re th at o bj e ct w as pl ace d u nde r th e co ntro l o f ano th e r e nti ty . If so , w e w o u l d ag ai n h av e a re so u rce l e ak . (A l l o w i ng e x ce pti o ns to e scape f ro m de stru cto rs i s rare l y a g o o d i de a: It m ak e s i t e asy f o r an e x ce pti o n to be th ro w n w h i l e th e cal l stack i s be i ng u nw o u nd f o r a pre v i o u s e x ce pti o n, and th i s l e ads to i m m e di ate te rm i nati o n o f th e pro g ram . T h e l atte r si tu ati o n can be g u arde d ag ai nst, bu t i t m ak e s f o r h arde r to u nde rstand—and th e re f o re m o re bri ttl e —co de .)

20.1.8 Trules

T o so l v e su ch pro bl e m s l e t' s i ntro du ce a h e l pe r cl ass te m pl ate de di cate d to transf e rri ng h o l de rs. W e cal l th i s cl ass te m pl ate a t r ul e , w h i ch i s a te rm de ri v e d f ro m th e co ntracti o n o f t r a ns f e r c a p s ul e . H e re i s i ts de f i ni ti o n:

// pointers/trule.hpp

Page 430: CPlusPlus Templates The Complete Guide

#ifndef TRULE_HPP #define TRULE_HPP template <typename T> class Holder; template <typename T> class Trule { private: T* ptr; // objects to which the trule refers (if any) public: // constructor to ensure that a trule is used only as a return type // to transfer holders from callee to caller! Trule (Holder<T>& h) { ptr = h.get(); h.release(); } // copy constructor Trule (Trule<T> const& t) { ptr = t.ptr; const_cast<Trule<T>&>(t).ptr = 0; } // destructor ~Trule() { delete ptr; } private: Trule(Trule<T>&); // discourage use of lvalue trules Trule<T>& operator= (Trule<T>&); // discourage copy assignment friend class Holder<T>; }; #endif // TRULE_HPP

C l e arl y , so m e th i ng u g l y i s g o i ng o n i n th e co py co nstru cto r. B e cau se transf e r capsu l e s are m e ant as th e re tu rn ty pe o f f u ncti o ns th at w i sh to transf e r h o l de rs, th e y al w ay s o ccu r as te m po rary o bj e cts (rv al u e s); h e nce th e y can be bo u nd o nl y to re f e re nce -to -const ty pe s. H o w e v e r, th e transf e r canno t j u st be a co py and m u st re m o v e th e o w ne rsh i p, by nu l l i ng th e e ncapsu l ate d po i nte r, f ro m th e o ri g i nal Trule. T h e l atte r o pe rati o n i s i ntri nsi cal l y no n-const. T h i s state o f af f ai rs i s u g l y , bu t i t i s i n f act l e g al to cast aw ay co nstne ss i n th e se case s be cau se th e o ri g i nal o bj e ct w as no t de cl are d const. H e nce , w e m u st be care f u l to de cl are th e re tu rn ty pe o f a f u ncti o n transf e rri ng a h o l de r as Trule<T> and no t Trule<T> const.

No te th at no su ch co de i s u se d f o r co nv e rti ng a h o l de r i nto a tru l e : T h e h o l de r m u st be a m o di f i abl e l v al u e . T h i s i s w h y w e u se a se parate ty pe f o r th e transf e r

Page 431: CPlusPlus Templates The Complete Guide

capsu l e i nste ad o f m e rg i ng th i s f u ncti o nal i ty i nto th e Holder cl ass te m pl ate .

T o di sco u rag e th e u se o f Trule as any th i ng bu t a re tu rn ty pe f o r transf e rri ng h o l de rs, a co py co nstru cto r tak i ng a re f e re nce to a no n-const o bj e ct and a si m i l ar co py -assi g nm e nt o pe rato r w e re de cl are d pri v ate . T h i s pre v e nts u s f ro m do i ng m u ch w i th l v al u e Trules, bu t i t i s o nl y a v e ry parti al m e asu re . T h e g o al o f a tru l e i s to h e l p th e re spo nsi bl e so f tw are e ng i ne e r, no t to th w art th e m ad sci e nti st.

T h e Trule te m pl ate i s no t co m pl e te u nti l i t i s re co g ni z e d by th e Holder te m pl ate :

// pointers/holder2extr.hpp template <typename T> class Holder { // previously defined members … public: Holder (Trule<T> const& t) { ptr = t.ptr; const_cast<Trule<T>&>(t).ptr = 0; } Holder<T>& operator= (Trule<T> const& t) { delete ptr; ptr = t.ptr; const_cast<Trule<T>&>(t).ptr = 0; return *this; } };

T o i l l u strate th i s re f i ne d Holder/Trule pai r, w e can re w ri te o u r load_something() e x am pl e and i nv e nt a cal l e r f o r i t:

// pointers/truletest.cpp #include "holder2.hpp" #include "trule.hpp" class Something { }; void read_something (Something* x) { } Trule<Something> load_something() { Holder<Something> result(new Something); read_something(result.get()); return result; }

Page 432: CPlusPlus Templates The Complete Guide

int main() { Holder<Something> ptr(load_something()); … }

T o co ncl u de , w e h av e cre ate d a pai r o f cl ass te m pl ate s th at are al m o st as co nv e ni e nt to u se as pl ai n po i nte rs w i th th e adde d be ne f i t o f m anag i ng th e de al l o cati o n o f o bj e cts ne ce ssary w h e n th e stack g e ts u nw o u nd as th e re su l t o f an e x ce pti o n be i ng th ro w n.

Page 433: CPlusPlus Templates The Complete Guide

20.2 Reference Counting

T h e Holder te m pl ate (and i ts Trule h e l pe r) w o rk s w e l l to h o l d al l o cate d stru ctu re s te m po rari l y so th at th e y w i l l be de al l o cate d i f an e x ce pti o n cau se s th e l o cal stack f ram e to be u nw o u nd. H o w e v e r, m e m o ry l e ak s can al so o ccu r i n o th e r co nte x ts, and i n parti cu l ar w h e n m any o bj e cts are i nte rco nne cte d i n co m pl e x stru ctu re s.

A g e ne ral ru l e abo u t th e m anag e m e nt o f dy nam i cal l y al l o cate d o bj e cts i s e asi l y state d: If no th i ng i n an appl i cati o n po i nts to a dy nam i cal l y al l o cate d o bj e ct, th at o bj e ct sh o u l d be de stro y e d and i ts sto rag e sh o u l d be m ade av ai l abl e f o r re u se . It i s th e re f o re no t su rpri si ng th at pro g ram m e rs e v e ry w h e re h av e be e n l o o k i ng f o r w ay s to au to m ate su ch a po l i cy . T h e ch al l e ng e i s to de te rm i ne th at no th i ng i s po i nti ng to an o bj e ct.

O ne i de a th at h as be e n i m pl e m e nte d m any ti m e s o v e r i s so -cal l e d r e f e r e nc e c ount i ng : F o r e ach o bj e ct th at i s po i nte d to , k e e p a co u nt o f th e nu m be r o f po i nte rs to i t, and w h e n th at co u nt dro ps to z e ro , de l e te th e o bj e ct. F o r th i s to be f e asi bl e i n C + + , w e ne e d to adh e re to so m e co nv e nti o n. S pe ci f i cal l y , be cau se i t i s no t practi cal to track h o w o rdi nary po i nte rs to an o bj e ct are cre ate d, co pi e d, and de stro y e d , i t i s co m m o n to re q u i re th at th e o nl y " po i nte rs" to a re f e re nce -co u nte d o bj e ct are a spe ci f i c k i nd o f sm art po i nte r. In th i s se cti o n w e di scu ss th e i m pl e m e ntati o n o f su ch a r e f e r e nc e -c ount i ng s m a r t p oi nt e r . T h i s po i nte r i s a te m pl ate w h o se m ai n param e te r i s th e ty pe o f th e o bj e ct to w h i ch i t po i nts:

template <typename T … > class CountingPtr { public: // a constructor that starts a new count for the object // pointed to by T: explicit CountingPtr (T*); // copying increases the count: CountingPtr (CountingPtr<T… > const&); // destruction decreases the count: inline ~CountingPtr(); // assignment decreases the count for the object previously // pointed to and increases it for the new object pointed to // (but beware of self-assignment): CountingPtr<T… >& operator= (CountingPtr<T… > const&); // the operators that make this a smart pointer: inline T& operator* (); inline T* operator-> (); …

Page 434: CPlusPlus Templates The Complete Guide

};

T h e param e te r T i s th e o nl y param e te r th at i s tru l y ne e de d to bu i l d a f u ncti o nal co u nti ng po i nte r te m pl ate . Inde e d, a g o o d case can be m ade i n f av o r o f k e e pi ng a basi c te m pl ate l i k e th i s as si m pl e and re l i abl e as po ssi bl e . No ne th e l e ss, w e ch o o se to u se CountingPtr to de m o nstrate p ol i c y param e te rs (a co nce pt de scri be d i n de tai l i n C h apte r 1 5 ).

T h e co m m e nts i n th e co de e x pl ai n th e g e ne ral appro ach to re f e re nce co u nti ng : E v e ry co nstru cti o n, de stru cti o n, and assi g nm e nt o f a CountingPtr m ay po te nti al l y ch ang e th e re f e re nce co u nts (w h e n o ne o f th e co u nts dro ps to z e ro , th e o bj e ct po i nte d to i s de l e te d).

20.2.1 Where Is the Counter?

B e cau se o u r i de a i s to co u nt th e nu m be r o f po i nte rs to an o bj e ct, i t w o u l d be e nti re l y l o g i cal to pl ace th e co u nte r i n th e o bj e ct. U nf o rtu nate l y , th i s i s no t v i abl e w h e n th e ty pe o f th e o bj e ct po i nte d to h as be e n de si g ne d w i th o u t re f e re nce co u nti ng i n m i nd.

If no co u nte r i s av ai l abl e i n a re f e re nce -co u nte d o bj e ct, th e co u nte r m u st be al l o cate d i n a se parate sto rag e are a th at i s at l e ast as l o ng -l i v e d as th e o bj e ct po i nte d to ; i n o th e r w o rds, i t m u st be dy nam i cal l y al l o cate d. U si ng th e pl ai n ::operator new th at co m e s w i th y o u r C + + co m pi l e r i s l i k e l y to re -su l t i n di sappo i nti ng pe rf o rm ance . Inde e d, ::operator new m u st be abl e to al l o cate q u asi -arbi trary o bj e ct si z e s w i th o u t e x ce ssi v e sto rag e o v e rh e ad, and th i s re q u i re s so m e co m pu tati o nal co m pro m i se s. Inste ad, f o r co u nti ng po i nte rs i t i s m o re co m m o n to u se a spe ci al -pu rpo se al l o cato r.

A l e ss co m m o n al te rnati v e to th e se parate al l o cati o n o f a co u nte r i s to u se a spe ci al -pu rpo se al l o cato r f o r th e re f e re nce -co u nte d o bj e ct. Inde e d, su ch an al l o cato r co u l d al l o cate so m e e x tra sto rag e to k e e p th e co u nte r.

Inste ad o f pre scri bi ng w h e re th e co u nte r i s l o cate d, w e l e av e th e l o cati o n o f th e co u nte r as a te m pl ate param e te r. In e f f e ct, th i s param e te r i s o u r c ount e r p ol i c y (se e C h apte r 1 5 ). T h i s po l i cy ' s i nte rf ace co u l d co nsi st si m pl y o f a f u ncti o n re tu rni ng an i nte g e r ty pe and o ne th at al l o cate s th at i nte g e r i f ne ce ssary . H o w e v e r, th e re are g o o d re aso ns to pro v i de a sl i g h tl y h i g h e r l e v e l i nte rf ace .

20.2.2 Concurrent Counter Access

In an e nv i ro nm e nt w i th o nl y o ne th re ad o f e x e cu ti o n, m anag i ng th e co u nte r i s strai g h tf o rw ard. Incre m e nti ng , de cre m e nti ng , and te sti ng f o r e q u al i ty w i th z e ro are basi c o pe rati o ns. H o w e v e r, i n m u l ti -th re ade d e nv i ro nm e nts a co u nte r can be sh are d by sm art po i nte rs o pe rati ng i n di f f e re nt th re ads o f e x e cu ti o n. In th i s case

Page 435: CPlusPlus Templates The Complete Guide

w e m ay ne e d to add sm art po i nte rs to th e co u nte r i tse l f so th at, f o r e x am pl e , si m u l tane o u s i ncre m e nt o pe rati o ns f ro m tw o th re ads are appro pri ate l y se q u e nce d. In practi ce th i s re q u i re s a f o rm o f (i m pl i ci t o r e x pl i ci t) l oc k i ng .

R ath e r th an spe ci f y i ng h o w th i s l o ck i ng i s do ne , w e spe ci f y f o r th e co u nte r an i nte rf ace th at i s o f a su f f i ci e ntl y h i g h l e v e l to i ntro du ce l o ck i ng o pe rati o ns. S pe ci f i cal l y , w e re q u i re th at a co u nte r be a cl ass w i th th e f o l l o w i ng i nte rf ace :

class CounterPolicy { public: // the following four special members (constructors, destructor, and // copy assignment) need not be declared explicitly in some cases, // but they must be accessible CounterPolicy(); CounterPolicy(CounterPolicy const&); ~CounterPolicy(); CounterPolicy& operator=(CounterPolicy const&); // assume T is the type of object pointed to void init(T*); // initialization to one, possibly allocation void dispose(T*); // possibly involves deallocation of the counter void increment(T*); // atomic increment by one void decrement(T*); // atomic decrement by one bool is_zero(T*); // check for zero … };

T h e ty pe T u se d i n th i s i nte rf ace i s pre su m abl y pro v i de d as a te m pl ate param e te r. It i s u se d o nl y by po l i ci e s th at u se th e o bj e ct po i nte d to to sto re th e co u nte r.

L o ck i ng th e co u nte r pro te cts co ncu rre nt acce ss o nl y to th e co u nte r and no t to th e CountingPtr i tse l f . H e nce , i f m u l ti pl e sm art po i nte rs to a u ni q u e o bj e ct are sh are d am o ng di f f e re nt th re ads o f e x e cu ti o n, an appl i cati o n m ay ne e d to i ntro du ce addi ti o nal l o ck s to se q u e nce th e CountingPtr o pe rati o ns co rre ctl y . T h e sm art po i nte r i tse l f , h o w e v e r, canno t be h e l d re spo nsi bl e f o r l o ck i ng at th at l e v e l .

20.2.3 Destruction and Deallocation

W h e n no co u nti ng po i nte rs are po i nti ng to an o bj e ct, o u r po l i cy i s to di spo se o f th at o bj e ct. In C + + th i s can o f te n be ach i e v e d u si ng th e standard delete o pe rato r. H o w e v e r, th i s i s no t al w ay s th e case . S o m e ti m e s o bj e cts m u st be de al l o cate d u si ng di f f e re nt f u ncti o ns, su ch as th e standard C f u ncti o n free(). F u rth e rm o re , i f th e o bj e ct po i nte d to i s re al l y an array , th e di spo sal m ay ne e d to

Page 436: CPlusPlus Templates The Complete Guide

u se o pe rato r delete[].

B e cau se w e anti ci pate th at th e re are su f f i ci e nt case s w h e n th e di spo sal o f th e o bj e ct w i l l be no nstandard, i t i s w o rth w h i l e to i ntro du ce a se parate ob j e c t p ol i c y f o r i t. Its i nte rf ace i s v e ry si m pl e :

class ObjectPolicy { public: // the following four special members (constructors, destructor, and // copy assignment) need not be declared explicitly in some cases, // but they must be accessible ObjectPolicy(); ObjectPolicy(CounterPolicy const&); ~ObjectPolicy(); ObjectPolicy& operator=(ObjectPolicy const&); // assume T is the type of object pointed to void dispose (T*); };

It i s po ssi bl e to e nri ch th i s po l i cy f o r o th e r o pe rati o ns th at m ay i nv o l v e th e o bj e ct po i nte d to (f o r e x am pl e , th e operator* and operator-> de re f e re nci ng o pe rato rs). O ne po pu l ar o pti o n i s to i nco rpo rate so m e ch e ck i ng ag ai nst de re f e re nci ng o u r sm art po i nte r w h e n i t i s no t actu al l y po i nti ng to any o bj e ct. O n th e o th e r h and i t i s al so e nti re l y po ssi bl e to add a spe ci f i c po l i cy param e te r f o r th i s so rt o f ch e ck i ng . In th e i nte re st o f bre v i ty w e do no t pu rsu e th i s o pti o n, bu t i t i s no t h ard to i m pl e m e nt i f y o u are co m f o rtabl e w i th th e re m ai nde r o f th i s se cti o n.

F o r m o st o bj e cts co u nte d by CountingPtrs, w e can u se th e f o l l o w i ng si m pl e o bj e ct po l i cy :

// pointers/stdobjpolicy.hpp class StandardObjectPolicy { public: template<typename T> void dispose (T* object) { delete object; } };

C l e arl y , th i s do e s no t w o rk f o r array s al l o cate d w i th o pe rato r new[]. A re pl ace m e nt po l i cy f o r th i s case i s tri v i al , f o rtu nate l y :

// pointers/stdarraypolicy.hpp class StandardArrayPolicy { public:

Page 437: CPlusPlus Templates The Complete Guide

template<typename T> void dispose (T* array) { delete[] array; } };

No te th at i n bo th case s w e ch o se to i m pl e m e nt dispose() as a m e m be r te m pl ate . W e co u l d al so h av e param e te ri z e d th e po l i cy cl ass i nste ad. A di scu ssi o n o f su ch al te rnati v e s can be f o u nd i n S e cti o n 1 5 .1 .6 o n pag e 2 5 9 .

20.2.4 The CountingPtr Template

No w th at w e h av e de ci de d o u r po l i cy i nte rf ace s, w e are re ady to i m pl e m e nt th e CountingPtr i nte rf ace i tse l f :

// pointers/countingptr.hpp template<typename T, typename CounterPolicy = SimpleReferenceCount, typename ObjectPolicy = StandardObjectPolicy> class CountingPtr : private CounterPolicy, private ObjectPolicy { private: // shortcuts: typedef CounterPolicy CP; typedef ObjectPolicy OP; T* object_pointed_to; // the object referred to (or NULL if none) public: // default constructor (no explicit initialization): CountingPtr() { this->object_pointed_to = NULL; } // a converting constructor (from a built-in pointer): explicit CountingPtr (T* p) { this->init(p); // init with ordinary pointer } // copy constructor: CountingPtr (CountingPtr<T,CP,OP> const& cp) : CP((CP const&)cp), // copy policies OP((OP const&)cp) { this->attach(cp); // copy pointer and increment counter } // destructor: ~CountingPtr() { this->detach(); // decrement counter // (and dispose counter if last owner) } // assignment of a built-in pointer CountingPtr<T,CP,OP>& operator= (T* p) { // no counting pointer should point to *p yet: assert(p != this->object_pointed_to); this->detach(); // decrement counter

Page 438: CPlusPlus Templates The Complete Guide

// (and dispose counter if last owner) this->init(p); // init with ordinary pointer return *this; } // copy assignment (beware of self-assignment): CountingPtr<T,CP,OP>& operator= (CountingPtr<T,CP,OP> const& cp) { if (this->object_pointed_to != cp.object_pointed_to) { this->detach(); // decrement counter // (and dispose counter if last owner) CP::operator=((CP const&)cp); // assign policies OP::operator=((OP const&)cp); this->attach(cp); // copy pointer and increment counter } return *this; } // the operators that make this a smart pointer: T* operator-> () const { return this->object_pointed_to; } T& operator* () const { return *this->object_pointed_to; } // additional interfaces will be added later … private: // helpers: // - init with ordinary pointer (if any) void init (T* p) { if (p != NULL) { CounterPolicy::init(p); } this->object_pointed_to = p; } // - copy pointer and increment counter (if any) void attach (CountingPtr<T,CP,OP> const& cp) { this->object_pointed_to = cp.object_pointed_to; if (cp.object_pointed_to != NULL) { CounterPolicy::increment(cp.object_pointed_to); } } // - decrement counter (and dispose counter if last owner) void detach() { if (this->object_pointed_to != NULL) { CounterPolicy::decrement(this->object_pointed_to); if (CounterPolicy::is_zero(this->object_pointed_to)) { // dispose counter, if necessary: CounterPolicy::dispose(this->object_pointed_to); // use object policy to dispose the object pointed to: ObjectPolicy::dispose(this->object_pointed_to); } } }

Page 439: CPlusPlus Templates The Complete Guide

};

T h e re i s re l ati v e l y l i ttl e co m pl e x i ty i n th i s te m pl ate , e x ce pt pe rh aps f o r th at f act th at th e co py -assi g nm e nt o pe rati o n m u st be care f u l w i th th e se l f -assi g nm e nt case . Inde e d, i n m o st case s th e assi g nm e nt o pe rato r can j u st de tach th e co u nti ng po i nte r f ro m th e o bj e ct to w h i ch i t u se d to po i nt, th e re by po ssi bl y de cre asi ng th e asso ci ate d co u nte r to z e ro and di spo si ng o f th e o bj e ct. H o w e v e r, i f th i s h appe ns w h e n th e co u nti ng po i nte r i s assi g ne d to i tse l f , th i s di spo sal i s pre m atu re (and i nco rre ct).

No te al so th at w e m u st e x pl i ci tl y ch e ck f o r th e nu l l po i nte r case be cau se a nu l l po i nte r do e s no t h av e an asso ci ate d co u nte r. A n al te rnati v e to o u r appro ach i s to l e av e th e ch e ck i ng to th e po l i cy cl asse s. In f act, a po ssi bl e po l i cy co u l d be no t to al l o w nu l l CountingPtrs at al l . W h e n su ch a po l i cy i s appl i cabl e , i t re su l ts i n sl i g h tl y i m pro v e d pe rf o rm ance .

W e u se i nh e ri tance to i ncl u de th e po l i ci e s. T h i s e nsu re s th at i f th e po l i ci e s are e m pty cl asse s, th e y do no t ne e d to tak e u p sto rag e (pro v i de d o u r co m pi l e r i m pl e m e nts th e e m pty base cl ass o pti m i z ati o n, se e S e cti o n 1 6 .2 o n pag e 2 8 9 ). W e co u l d u se th e BaseMemberPair te m pl ate i ntro du ce d i n S e cti o n 1 6 .2 .2 o n pag e 2 9 4 to av o i d h av i ng th e m e m be rs o f th e po l i cy cl asse s be v i si bl e i n th e sm art po i nte r cl ass. In th i s e x am pl e w e ch o se to av o i d m ak i ng th e so u rce co de m o re co m pl i cate d f o r th e sak e o f k e e pi ng th e di scu ssi o n si m pl e r.

B e cau se th e re i s m o re th an o ne de f au l t te m pl ate arg u m e nt, i t co u l d be be ne f i ci al to u se th e te ch ni q u e o f S e cti o n 1 6 .1 o n pag e 2 8 5 to o v e rri de th e de f au l ts co nv e ni e ntl y and se l e cti v e l y . A g ai n, w e di d no t do so h e re f o r th e sak e o f bre v i ty .

20.2.5 A Simple Noninvasive Counter

A l th o u g h w e h av e co m pl e te d th e de si g n o f o u r CountingPtr, w e h av e n' t actu al l y f i ni sh e d i m p l e m e nt i ng th e de si g n. T h e re i s no co de y e t f o r a co u nte r po l i cy . L e t' s f i rst l o o k at a po l i cy f o r a co u nte r th at i s not sto re d i n th e o bj e ct po i nte d to —th at i s, a noni nv a s i v e (o r noni nt r us i v e ) co u nte r po l i cy .

T h e m ai n i ssu e w i th o u r co u nte r i s i ts al l o cati o n. Inde e d, th e co u nte r m ay ne e d to be sh are d by m any CountingPtrs; h e nce i t m u st be g i v e n a l i f e ti m e th at l asts u nti l th e l ast sm art po i nte r i s de stro y e d. U su al l y th i s i s do ne u si ng a spe ci al -pu rpo se al l o cato r spe ci al i z e d f o r th e al l o cati o n o f sm al l o bj e cts o f a f i x e d si z e . H o w e v e r, be cau se th e de si g n o f su ch al l o cato rs i s no t parti cu l arl y pe rti ne nt to th e to pi c o f C + + te m pl ate s, w e f o rg o th e i n-de pth di scu ssi o n o f an i ndu stri al -stre ng th al l o cato r. [3 ] Inste ad, l e t' s assu m e th e e x i ste nce o f f u ncti o ns alloc_counter() and dealloc_counter() th at m anag e sto rag e o f ty pe size_t. W i th th e se assu m pti o ns, w e can w ri te o u r si m pl e co u nte r as f o l l o w s:

Page 440: CPlusPlus Templates The Complete Guide

[3 ] A l l o cato rs can be param e te ri z e d i n al l so rts o f w ay s (f o r e x am pl e , to se l e ct po l i ci e s w i th re f e re nce to co ncu rre nt acce ss), bu t w e do no t th i nk th i s si g ni f i cantl y adds to o u r u nde rstandi ng o f te m pl ate s and th e i r appl i cati o ns.

// pointers/simplerefcount.hpp #include <stddef.h> // for the definition of size_t #include "allocator.hpp" class SimpleReferenceCount { private: size_t* counter; // the allocated counter public: SimpleReferenceCount () { counter = NULL; } // default copy constructor and copy-assignment operator // are fine in that they just copy the shared counter public: // allocate the counter and initialize its value to one: template<typename T> void init (T*) { counter = alloc_counter(); *counter = 1; } // dispose of the counter: template<typename T> void dispose (T*) { dealloc_counter(counter); } // increment by one: template<typename T> void increment (T*) { ++*counter; } // decrement by one: template<typename T> void decrement (T*) { --*counter; } // test for zero: template<typename T> bool is_zero (T*) { return *counter == 0; } };

B e cau se th i s po l i cy i s no ne m pty (i t sto re s a po i nte r to th e co u nte r), i t i ncre ase s th e si z e o f a CountingPtr. T h e si z e can be re du ce d by sto ri ng th e po i nte r to th e o bj e ct al o ng si de th e co u nte r i nste ad o f pl aci ng i t di re ctl y i n th e sm art po i nte r cl ass. D o i ng so re q u i re s a ch ang e i n o u r po l i cy de si g n and de cre ase s th e pe rf o rm ance o f acce ssi ng th e o bj e ct by re q u i ri ng an addi ti o nal l e v e l o f i ndi re cti o n.

No te al so th at th i s parti cu l ar po l i cy do e sn' t m ak e u se o f th e co u nte d o bj e ct i tse l f .

Page 441: CPlusPlus Templates The Complete Guide

In o th e r w o rds, th e param e te r passe d to i ts m e m be r f u ncti o ns i s ne v e r u se d. In th e f o l l o w i ng se cti o n w e se e an al te rnati v e po l i cy th at do e s m ak e u se o f th i s param e te r.

20.2.6 A Simple Invasive Counter Template

A n i nv a s i v e (o r i nt r us i v e ) co u nte r po l i cy i s o ne th at pl ace s th e co u nte r i n th e ty pe o f th e m anag e d o bj e cts th e m se l v e s (o r pe rh aps i n so m e sto rag e co ntro l l e d by th e se m anag e d o bj e cts). T h i s no rm al l y ne e ds to be de si g ne d at th e ti m e th e o bj e ct ty pe i s de si g ne d; h e nce th e so l u ti o n i s l i k e l y to be v e ry spe ci f i c to th at ty pe . H o w e v e r, f o r i l l u strati v e pu rpo se s w e de v e l o p a m o re g e ne ri c i nv asi v e po l i cy .

T o se l e ct th e l o cati o n o f th e co u nte r i n th e re f e re nce d o bj e ct l e t' s u se a no nty pe po i nte r-to -m e m be r param e te r. B e cau se th e co u nte r i s al l o cate d as part o f th e o bj e ct, th e i m pl e m e ntati o n o f th i s po l i cy i s i n so m e w ay s si m pl e r th an o u r no ni nv asi v e e x am pl e , bu t th e po i nte r-to -m e m be r sy ntax i s a l i ttl e l e ss co m m o n:

// pointers/memberrefcount.hpp template<typename ObjectT, // the class type containing the counter typename CountT, // the type of the pointer CountT ObjectT::*CountP> // the location of the counter class MemberReferenceCount { public: // the default constructor and destructor are fine // initialize the counter to one: void init (ObjectT* object) { object->*CountP = 1; } // no action is needed to dispose of the counter: void dispose (ObjectT*) { } // increment by one: void increment (ObjectT* object) { ++object->*CountP; } // decrement by one: void decrement (ObjectT* object) { --object->*CountP; } // test for zero: template<typename T> bool is_zero (ObjectT* object) { return object->*CountP == 0; } };

Page 442: CPlusPlus Templates The Complete Guide

T h i s po l i cy al l o w s a cl ass i m pl e m e nte r to pro v i de a re f e re nce -co u nti ng po i nte r ty pe q u i ck l y f o r th e cl ass. T h e o u tl i ne o f th e de si g n o f su ch a cl ass co u l d be as f o l l o w s:

class ManagedType { private: size_t ref_count; public: typedef CountingPtr<ManagedType, MemberReferenceCount <ManagedType, size_t, &ManagedType::ref_count> > Ptr; … };

W i th th i s appro ach , ManagedType::Ptr i s a co nv e ni e nt w ay to re f e r to th e sm art po i nte r ty pe th at sh o u l d be u se d to acce ss a ManagedType o bj e ct.

20.2.7 Constness

In C + + th e ty pe s X const* and X* const are di sti nct. T h e f o rm e r i ndi cate s th at th e e l e m e nt po i nte d to sh o u l d no t be m o di f i e d, w h e re as th e l atte r i ndi cate s th at th e po i nte r i tse l f canno t be m o di f i e d. T h e sam e du al i ty e x i sts w i th o u r re f e re nce co u nti ng po i nte r: X const* co rre spo nds to CountingPtr<X const> w h e re as X* const co rre spo nds to CountingPtr<X> const. In o th e r w o rds, th e co nstne ss o f th e o bj e ct po i nte d to i s a pro pe rty o f th e te m pl ate arg u m e nt. L e t' s l o o k at so m e o f th e pu bl i c m e m be r f u ncti o ns o f CountingPtr to se e h o w th e y are af f e cte d by th i s o bse rv ati o n.

T h e de re f e re nci ng o pe rato rs do no t m o di f y th e po i nte r, w h i ch i s w h y th e y are const m e m be r f u ncti o ns. H o w e v e r, th e y do pro v i de acce ss to th e o bj e ct po i nte d to . B e cau se th e co nstne ss o f th i s o bj e ct i s captu re d by th e te m pl ate param e te r T , T can be u se d w i th o u t adde d q u al i f i cati o n i n th e re tu rn ty pe o f th e se o pe rato rs.

A n int* canno t be i ni ti al i z e d by an int const* be cau se th i s w o u l d cre ate a w ay to m o di f y an o bj e ct th ro u g h an e nti ty th at w asn' t m e ant to pro v i de th at k i nd o f m u tabl e acce ss. In th e sam e v e i n, w e m u st e nsu re th at a CountingPtr<int> canno t be i ni ti al i z e d by a CountingPtr<int const> o r e v e n by a int const*. A g ai n, u si ng th e pl ai n (no t const-q u al i f i e d) te m pl ate param e te r T ach i e v e s th e de si re d e f f e ct. T h i s m ay se e m strai g h tf o rw ard, bu t sm art po i nte r i m pl e m e ntati o ns th at de cl are a co nstru cto r o r assi g nm e nt o pe rato r acce pti ng a T const* are q u i te co m m o n (and pre su m abl y e rro ne o u s).

Page 443: CPlusPlus Templates The Complete Guide

T h e assi g nm e nt o pe rato rs are su bj e ct to th e sam e o bse rv ati o ns as th e co nstru cto rs. Natu ral l y , su ch o pe rato rs are ne v e r const th e m se l v e s.

20.2.8 Implicit Conversions

B u i l t-i n po i nte rs are su bj e ct to se v e ral i m pl i ci t co nv e rsi o ns:

• C o nv e rsi o n to void* • C o nv e rsi o n to a po i nte r to a base su bo bj e ct o f th e o bj e ct po i nte d to • C o nv e rsi o n to bool (false i f th e po i nte r i s nu l l , true o th e rw i se )

W e m ay w ant to e m u l ate th e se i n o u r CountingPtr te m pl ate , bu t do i ng so i s no t tri v i al , as w e sh al l se e . In addi ti o n, so m e pro g ram m e rs l i k e th e i r sm art po i nte rs to h av e a co nv e rsi o n to a co rre spo ndi ng bu i l t-i n po i nte r ty pe (f o r e x am pl e , so m e l i k e CountingPtr<int const> to be co nv e rti bl e to int const*).

U nf o rtu nate l y , e nabl i ng i m pl i ci t co nv e rsi o ns to bu i l t-i n po i nte r ty pe s cre ate s a l o o ph o l e i n th e assu m pti o n th at a l l th e po i nte rs to a re f e re nce -co u nte d o bj e ct are CountingPtrs. W e th e re f o re ch o o se no t to pro v i de su ch a co nv e rsi o n. T h e re f o re , a CountingPtr<X> canno t i m pl i ci tl y be co nv e rte d to void* o r to X*.

O th e r draw back s to i m pl i ci t co nv e rsi o ns to bu i l t-i n po i nte r ty pe s i ncl u de (assu m e cp i s an co u nti ng po i nte r):

• delete cp; and ::delete cp; be co m e v al i d • A l l so rts o f m e ani ng l e ss po i nte r ari th m e ti c g o e s u ndi ag no se d (f o r e x am pl e ,

cp[n] , cp2 - cp1, and so f o rth )

O n th e o th e r h and, i m pl i ci t co nv e rsi o ns to o th e r CountingPtr spe ci al i z ati o ns can m ak e pe rf e ct se nse . F o r e x am pl e , w e can i m ag i ne an i m pl i ci t co nv e rsi o n to CountingPtr<void> (th e l atte r can be a u se f u l o paq u e po i nte r ty pe , j u st l i k e void*). T h e re i s a l i m i tati o n, h o w e v e r: A n i nv asi v e co u nte r po l i cy canno t acco m m o date su ch a co nv e rsi o n be cau se th e void ty pe do e sn' t co ntai n a co u nte r. S i m i l arl y , a base cl ass m ay no t be co m pati bl e w i th an i nv asi v e co u nte r po l i cy e i th e r.

No ne th e l e ss, w e can add su ch i m pl i ci t co nv e rsi o ns to o u r CountingPtr te m pl ate . Instanti ati o n e rro rs o ccu r w h e n atte m pti ng co nv e rsi o ns th at are no t co m pati bl e w i th a g i v e n co u nte r po l i cy . T h e i m pl i ci t co nv e rsi o ns m i g h t l o o k as f o l l o w s:

template<typename T, typename CounterPolicy = SimpleReferenceCount,

Page 444: CPlusPlus Templates The Complete Guide

typename ObjectPolicy = StandardObjectPolicy> class CountingPtr : private CounterPolicy, private ObjectPolicy { private: // Shortcuts: typedef CounterPolicy CP; typedef ObjectPolicy OP; … public: // add a converting constructor and make sure it can access // the private components of other instantiations: friend template<typename T2, typename CP2, typename OP2> class CountingPtr; template <typename S> // S could be void or a base of T CountingPtr(CountingPtr<S, OP, CP> const& cp) : OP((OP const&)cp), CP((CP const&)cp), object_pointed_to(cp.object_pointed_to) { if (cp.object_pointed_to != NULL) { CP::increment(cp.object_pointed_to); } } };

No te th at i n th i s case a co nv e rti ng co nstru cto r m o re e asi l y e nabl e d th e de si re d i m pl i ci t co nv e rsi o ns th an a co nv e rsi o n o pe rato r. In parti cu l ar, w e m u st m ak e su re th at th e re f e re nce co u nt i s co rre ctl y co pi e d.

T h e co nv e rsi o n to bool m ay se e m strai g h tf o rw ard. W e can j u st add a u se r-de f i ne d co nv e rsi o n o pe rato r to CountingPtr:

template<typename T, typename CounterPolicy = SimpleReferenceCount, typename ObjectPolicy = StandardObjectPolicy> class CountingPtr : private CounterPolicy, private ObjectPolicy { … public: operator bool() const { return this->object_pointed_to != (T*)0; } };

T h i s w o rk s, bu t i t al so al l o w s su rpri si ng and u ni nte nti o nal o pe rati o ns o n CountingPtrs. F o r e x am pl e , w i th th i s co nv e rsi o n i n pl ace , w e can add tw o CountingPtrs! T h i s i s su f f i ci e ntl y se ri o u s th at w e pre f e r no t to pro v i de th at o pe rato r.

T h e co nv e rsi o n to bool i s m o stl y u se f u l to su ppo rt co nstru cts o f th e f o rm

if (cp) …

Page 445: CPlusPlus Templates The Complete Guide

o r

while (!cp) …

T h e re f o re , th i s pro bl e m h as tradi ti o nal l y be e n w o rk e d aro u nd by pro v i di ng a co nv e rsi o n to void* (w h i ch i n tu rn i s i m pl i ci tl y co nv e rte d to bool i n j u st th e ri g h t pl ace s). [4 ] T h i s appro ach h as i ts o w n draw back s i n g e ne ral , bu t i t h as th e m e spe ci al l y f o r a sm art po i nte r f o r w h i ch w e al re ady de ci de d no t to pro v i de an i m pl i ci t co nv e rsi o n to void*.

[4 ] F o r e x am pl e , th i s i s do ne i n th e standard C + + stre am cl asse s.

A si m pl e (bu t o f te n o v e rl o o k e d) so l u ti o n to th i s pro bl e m i s to de f i ne a co nv e rsi o n to a po i nte r-to -m e m b e r ty pe i nste ad o f to a bu i l t-i n ty pe . Inde e d, po i nte r-to -m e m be r ty pe s al so su ppo rt i m pl i ci t co nv e rsi o n to bool, bu t u nl i k e re g u l ar po i nte rs th e y ' re no t v al i d ty pe s f o r o pe rato r delete o r f o r po i nte r ari th m e ti c. T h e f o l l o w i ng addi ti o n to o u r CountingPtr te m pl ate i l l u strate s h o w to appl y th i s te ch ni q u e :

template<typename T, typename CounterPolicy = SimpleReferenceCount, typename ObjectPolicy = StandardObjectPolicy> class CountingPtr : private CounterPolicy, private ObjectPolicy { … private: class BoolConversionSupport { int dummy; }; public: operator BoolConversionSupport::*() const { return this->object_pointed_to ? &BoolConversionSupport::dummy : 0; } … };

No te th at th i s do e s not i ncre ase th e si z e o f a CountingPtr be cau se no data m e m be rs are adde d. B y u si ng a pri v ate ne ste d cl ass w e av o i d po te nti al co nf l i cts w i th cl i e nt co de .

20.2.9 Comparisons

W e co ncl u de o u r di scu ssi o n o f co u nti ng po i nte rs w i th th e de v e l o pm e nt o f v ari o u s co m pari so n o pe rato rs f o r su ch po i nte rs. B u i l t-i n po i nte rs su ppo rt bo th e q u al i ty o pe rato rs (== and !=) and o rde ri ng o pe rato rs (<, <=, and so f o rth ).

Page 446: CPlusPlus Templates The Complete Guide

F o r bu i l t-i n po i nte rs, o rde ri ng o pe rato rs are g u arante e d to w o rk o nl y o n tw o po i nte rs th at po i nt to th e sam e array , bu t th i s i s no t a u se f u l sce nari o f o r co u nti ng po i nte rs. C o u nti ng po i nte rs al w ay s po i nt to a si ng l e o bj e ct o r to th e h e ad o f an array . T h u s, w e do n' t di scu ss th e se o pe rato rs i n th e te x t th at f o l l o w s. (H o w e v e r, th e o pe rato rs co u l d be i m pl e m e nte d f o r CountingPtr al o ng th e sam e l i ne s as th e e q u al i ty o pe rato rs i f an o rde ri ng w as ne e de d am o ng CountingPtrs.)

H e re are th e de tai l s o f o pe rato r == (o pe rato r != i s si m i l ar):

template<typename T, typename CounterPolicy = SimpleReferenceCount, typename ObjectPolicy = StandardObjectPolicy> class CountingPtr : private CounterPolicy, private ObjectPolicy { … public: friend bool operator==(CountingPtr<T,CP,OP> const& cp, T const* p) { return cp == p; } friend bool operator==(T const* p, CountingPtr<T,CP,OP> const& cp) { return p == cp; } }; template <typename T1, typename T2, typename CP, typename OP> inline bool operator== (CountingPtr<T1,CP,OP> const& cp1, CountingPtr<T2,CP,OP> const& cp2) { return cp1.operator->() == cp2.operator->(); }

T h e o u t-o f -cl ass o pe rato r i s a te m pl ate , w h i ch al l o w s u s to co m pare co u nti ng po i nte rs to di f f e re nt ty pe s. Its i m pl e m e ntati o n al l o w s u s to de m o nstrate th at i t i s po ssi bl e to e x tract th e bu i l t-i n po i nte r e ncapsu l ate d by CountingPtr. T h e e x pl i ci t operator-> i nv o cati o n th at th i s re q u i re s i s u nu su al e no u g h to draw o u r atte nti o n th at so m e th i ng po te nti al l y u nsaf e i s g o i ng o n.

T w o o th e r o pe rato rs are pro v i de d as no nte m pl ate o pe rato rs. B e cau se th e se o pe rato rs sti l l m u st de pe nd o n te m pl ate param e te rs, th e y m u st be i m pl e m e nte d as i n-cl ass f ri e nd de f i ni ti o ns. B e cau se th e y are no nte m pl ate s, th e o rdi nary i m pl i ci t co nv e rsi o ns appl y to th e i r arg u m e nts. T h i s i ncl u de s th e i m pl i ci t co nv e rsi o n o f z e ro to a nu l l po i nte r v al u e .

Page 447: CPlusPlus Templates The Complete Guide

20.3 Afternotes

S m art po i nte r te m pl ate s are pro babl y th e se co nd-m o st o bv i o u s appl i cati o n o f te m pl ate s af te r co ntai ne r te m pl ate s; h o w e v e r, th e de tai l s are f ar f ro m o bv i o u s, as th i s ch apte r i l l u strate s. Inde e d, m any au th o rs co v e r th e to pi c i n so m e de tai l . G o o d m ate ri al su ppl e m e nti ng o u r di scu ssi o n can be f o u nd i n [M e y e rsM o re E f f e cti v e ], w h i ch o f f e rs a m o re basi c di scu ssi o n, and i n [A l e x andre scu D e si g n], w h i ch de scri be s a co m pl e te , po l i cy -base d de si g n o f a f am i l y o f sm art po i nte rs.

T h e C + + standard l i brary co ntai ns a sm art po i nte r te m pl ate auto_ptr. It i s i nte nde d f o r th e sam e u se as o u r Holder/Trule pai r o f te m pl ate s, bu t av o i ds th e u se o f a se co nd te m pl ate by e x pl o i ti ng a co ntro v e rsi al pi e ce o f th e C + + o v e rl o adi ng ru l e s i n th e co nte x t o f v ari abl e i ni ti al i z ati o n. [5 ]

[5 ] A n e x pl anati o n o f th e m e ch ani sm s i nv o l v e d i s w e l l be y o nd th e sco pe o f th i s te x t (and no t re al l y re l ate d to te m pl ate s). T h e co ntro v e rsy ari se s be cau se o ne o f th e m e ch ani sm s o n w h i ch auto_ptr re l i e s i s co nsi de re d by so m e to be a de f e ct i n th e C + + standard. S e e [J o su tti sA u to P tr] f o r addi ti o nal di scu ssi o n o n th i s to pi c.

O th e r sm art po i nte rs w e re pro po se d f o r i ncl u si o n i n th e C + + standard l i brary , bu t th e C + + standardi z ati o n co m m i tte e de ci de d no t to su ppo rt th e m .

T h e B o o st pro j e ct o f f e rs a l i brary co ntai ni ng a v ari e ty o f sm art po i nte r cl asse s to m e e t a v ari e ty o f ne e ds (se e [B o o stS m artP tr]).

Page 448: CPlusPlus Templates The Complete Guide

Chapter 21. Tuples

T h ro u g h o u t th i s bo o k w e o f te n u se h o m o g e ne o u s co ntai ne rs and array -l i k e ty pe s to i l l u strate th e po w e r o f te m pl ate s. S u ch h o m o g e ne o u s stru ctu re s e x te nd th e co nce pt o f a C /C + + array and are pe rv asi v e i n m o st appl i cati o ns. C + + (and C ) al so h as a no nh o m o g e ne o u s co ntai nm e nt f aci l i ty : th e cl ass (o r stru ct). T u pl e s are cl ass te m pl ate s th at si m i l arl y al l o w u s to ag g re g ate o bj e cts o f di f f e ri ng ty pe s. W e start w i th th e duo—an e nti ty anal o g o u s to th e standard std::pair te m pl ate —bu t w e al so sh o w h o w i t can be ne ste d to asse m bl e an arbi trary nu m be r o f m e m be rs, th e re by f o rm i ng tri o s, q u arte ts, and so f o rth . [1]

[1] T h e nu m be r i s no t e nti re l y arbi trary be cau se th e re e x i sts an i m pl e m e ntati o n-de pe nde nt l i m i t o n th e de pth o f te m pl ate ne sti ng .

Page 449: CPlusPlus Templates The Complete Guide

21.1 Duos

A du o i s th e asse m bl y o f tw o o bj e cts i nto a si ng l e ty pe . T h i s i s si m i l ar to th e std::pair cl ass te m pl ate i n th e standard l i brary , bu t be cau se w e w i l l add sl i g h tl y di f f e re nt f u ncti o nal i ty to th i s v e ry basi c u ti l i ty , w e o pte d f o r a nam e o th e r th an pair to av o i d co nf u si o n w i th th e standard i te m . A t i ts v e ry si m pl e st, w e can de f i ne Duo as f o l l o w s:

template <typename T1, typename T2> struct Duo { T1 v1; // value of first field T2 v2; // value of second field };

T h i s can, f o r e x am pl e , be u se f u l as a re tu rn ty pe f o r a f u ncti o n th at m ay re tu rn an i nv al i d re su l t:

Duo<bool,X> result = foo(); if (result.v1) { // result is valid; value is in result.v2 … }

M any o th e r appl i cati o ns are po ssi bl e .

T h e be ne f i t o f Duo as de f i ne d h e re i s no t i nsi g ni f i cant, bu t i t i s rath e r sm al l . A f te r al l , i t w o u l d no t be th at m u ch w o rk to de f i ne a stru ctu re w i th tw o f i e l ds, and do i ng so al l o w s u s to ch o o se m e ani ng f u l nam e s f o r th e se f i e l ds. H o w e v e r, w e can e x te nd th e basi c f aci l i ty i n a f e w w ay s to add to th e co nv e ni e nce . F i rst, w e can add co nstru cto rs:

template <typename T1, typename T2> class Duo { public: T1 v1; // value of first field T2 v2; // value of second field // constructors Duo() : v1(), v2() { } Duo (T1 const& a, T2 const& b) : v1(a), v2(b) { } };

No te th at w e u se d an i ni ti al i z e r l i st f o r th e de f au l t co nstru cto r so th at th e

Page 450: CPlusPlus Templates The Complete Guide

m e m be rs g e t z e ro i ni ti al i z e d f o r bu i l t-i n ty pe s (se e S e cti o n 5 .5 o n pag e 5 6 ).

T o av o i d th e ne e d f o r e x pl i ci t ty pe param e te rs, w e can f u rth e r add a f u ncti o n so th at th e f i e l d ty pe s can be de du ce d:

template <typename T1, typename T2> inline Duo<T1,T2> make_duo (T1 const& a, T2 const& b) { return Duo<T1,T2>(a,b); }

No w th e cre ati o n and i ni ti al i z ati o n o f a Duo be co m e s m o re co nv e ni e nt. Inste ad o f

Duo<bool,int> result; result.v1 = true; result.v2 = 42; return result;

w e can w ri te

return make_duo(true,42);

G o o d C + + co m pi l e rs can o pti m i z e th i s w e l l e no u g h so th at th i s g e ne rate s co de e q u i v al e nt to

return Duo<bool,int>(true,42);

A no th e r re f i ne m e nt i s to pro v i de acce ss to th e f i e l d ty pe s, so th at adapte r te m pl ate s can be bu i l t o n to p o f Duo:

template <typename T1, typename T2> class Duo { public: typedef T1 Type1; // type of first field typedef T2 Type2; // type of second field enum { N = 2 }; // number of fields T1 v1; // value of first field T2 v2; // value of second field // constructors Duo() : v1(), v2() { } Duo (T1 const& a, T2 const& b) : v1(a), v2(b) { } };

Page 451: CPlusPlus Templates The Complete Guide

A t th i s stag e w e ' re rath e r cl o se to th e i m pl e m e ntati o n o f std::pair w i th th e f o l l o w i ng di f f e re nce s:

• W e u se di f f e re nt nam e s. • W e pro v i de a m e m be r N f o r th e nu m be r o f f i e l ds. • W e h av e no m e m be r te m pl ate i ni ti al i z ati o n to al l o w i m pl i ci t ty pe

co nv e rsi o ns du ri ng co nstru cti o n. • W e do n' t pro v i de co m pari so n o pe rato rs.

A m o re po w e rf u l and cl e ane r i m pl e m e ntati o n m i g h t l o o k s as f o l l o w s:

// tuples/duo1.hpp #ifndef DUO_HPP #define DUO_HPP template <typename T1, typename T2> class Duo { public: typedef T1 Type1; // type of first field typedef T2 Type2; // type of second field enum { N = 2 }; // number of fields private: T1 value1; // value of first field T2 value2; // value of second field public: // constructors Duo() : value1(), value2() { } Duo (T1 const & a, T2 const & b) : value1(a), value2(b) { } // for implicit type conversion during construction template <typename U1, typename U2> Duo (Duo<U1,U2> const & d) : value1(d.v1()), value2(d.v2()) { } // for implicit type conversion during assignments template <typename U1, typename U2> Duo<T1, T2>& operator = (Duo<U1,U2> const & d) { value1 = d.value1; value2 = d.value2; return *this; } // field access T1& v1() { return value1; } T1 const& v1() const { return value1;

Page 452: CPlusPlus Templates The Complete Guide

} T2& v2() { return value2; } T2 const& v2() const { return value2; } }; // comparison operators (allow mixed types): template <typename T1, typename T2, typename U1, typename U2> inline bool operator == (Duo<T1,T2> const& d1, Duo<U1,U2> const& d2) { return d1.v1()==d2.v1() && d1.v2()==d2.v2(); } template <typename T1, typename T2, typename U1, typename U2> inline bool operator != (Duo<T1,T2> const& d1, Duo<U1,U2> const& d2) { return !(d1==d2); } // convenience function for creation and initialization template <typename T1, typename T2> inline Duo<T1,T2> make_duo (T1 const & a, T2 const & b) { return Duo<T1,T2>(a,b); } #endif // DUO_HPP

W e m ade th e f o l l o w i ng ch ang e s:

• W e m ade th e data m e m be rs pri v ate and adde d acce ss f u ncti o ns. • W i th th e e x pl i ci t i ni ti al i z ati o n o f bo th m e m be rs i n th e de f au l t co nstru cto r •

• template <typename T1, typename T2> • class Duo {

• …

• Duo() : value1(), value2() { • }

• … }

w e m ade su re th at v al u e s o f bu i l t-i n ty pe s are z e ro i ni ti al i z e d (se e S e cti o n 5 .5 o n pag e 5 6 ).

• W e pro v i de d m e m be r te m pl ate s so th at co nstru cti o n and i ni ti al i z ati o n are po ssi bl e w i th m i x e d ty pe s.

• W e pro v i de d co m pari so n o pe rato rs == and !=. No te th at w e i ntro du ce d

Page 453: CPlusPlus Templates The Complete Guide

se parate se ts o f te m pl ate param e te rs f o r bo th si de s o f a co m pari so n to al l o w f o r co m pari so ns o f m i x e d ty pe s.

A l l th e m e m be r te m pl ate s are u se d to e nabl e m i x e d ty pe o pe rati o ns. T h at i s, w e can i ni ti al i z e , assi g n, and co m pare a Duo f o r w h i ch an i m pl i ci t ty pe co nv e rsi o n i s ne ce ssary to pe rf o rm th e task . F o r e x am pl e :

// tuples/duo1.cpp #include "duo1.hpp" Duo<float,int> foo () { return make_duo(42,42); } int main() { if (foo() == make_duo(42,42.0)) { … } }

In th i s pro g ram , i n foo() th e re i s a co nv e rsi o n f ro m th e re tu rn ty pe o f make_duo() , Duo<int,int> to th e re tu rn ty pe o f foo(), Duo<float,int>. S i m i l arl y , th e re tu rn v al u e o f foo() i s co m pare d w i th th e re tu rn v al u e o f make_duo(42, 42.0), w h i ch i s a Duo<int,double>.

It w o u l d no t be di f f i cu l t to add Trio and o th e r te m pl ate s to co l l e ct l arg e r nu m be rs o f v al u e s. H o w e v e r, a m o re stru ctu re d al te rnati v e can be o btai ne d by ne sti ng Duo o bj e cts. T h i s i de a i s de v e l o pe d i n th e f o l l o w i ng se cti o ns.

Page 454: CPlusPlus Templates The Complete Guide

21.2 Recursive Duos

C o nsi de r th e f o l l o w i ng o bj e ct de f i ni ti o n:

Duo<int, Duo<char, Duo<bool, double> > > q4;

T h e ty pe o f q4 i s a so -cal l e d r e c ur s i v e duo. It i s a ty pe i nstanti ate d f ro m th e Duo te m pl ate , and th e se co nd ty pe arg u m e nt i s i tse l f a Duo as w e l l . W e co u l d al so u se re cu rsi o n o f th e f i rst param e te r, bu t i n th e re m ai nde r o f th i s di scu ssi o n, r e c ur s i v e duo re f e rs o nl y to Duos w i th a se co nd te m pl ate arg u m e nt th at i s i nstanti ate d f ro m th e Duo te m pl ate .

21.2.1 Number of Fields

It' s re l ati v e l y strai g h tf o rw ard to co u nt th at q4 co l l e cts f o u r v al u e s o f ty pe s int, char, bool, and double re spe cti v e l y . T o f aci l i tate th e f o rm al co u nti ng o f th e nu m be r o f f i e l ds, w e can f u rth e r parti al l y spe ci al i z e th e Duo te m pl ate :

// tuples/duo2.hpp template <typename A, typename B, typename C> class Duo<A, Duo<B,C> > { public: typedef A T1; // type of first field typedef Duo<B,C> T2; // type of second field enum { N = Duo<B,C>::N + 1 }; // number of fields private: T1 value1; // value of first field T2 value2; // value of second field public: // the other public members are unchanged … };

F o r co m pl e te ne ss, l e t' s pro v i de a parti al spe ci al i z ati o n o f Duo so th at i t can de g e ne rate i nto a no nh o m o g e ne o u s co ntai ne r h o l di ng j u st o ne f i e l d:

// tuples/duo6.hpp // partial specialization for Duo<> with only one field template <typename A> struct Duo<A,void> { public: typedef A T1; // type of first field typedef void T2; // type of second field

Page 455: CPlusPlus Templates The Complete Guide

enum { N = 1 }; // number of fields private: T1 value1; // value of first field public: // constructors Duo() : value1() { } Duo (T1 const & a) : value1(a) { } // field access T1& v1() { return value1; } T1 const& v1() const { return value1; } void v2() { } void v2() const { } … };

No te th at th e v2() m e m be rs are n' t re al l y m e ani ng f u l i n th e parti al spe ci al i z ati o n, bu t o ccasi o nal l y i t i s u se f u l to h av e th e m f o r o rth o g o nal i ty .

21.2.2 Type of Fields

A re cu rsi v e du o i s no t re al l y h andy co m pare d w i th , say , a Trio o r Quartet cl ass th at w e co u l d w ri te . F o r e x am pl e , to acce ss th e th i rd v al u e o f th e q4 o bj e ct i n th e pre v i o u s co de , w e ' d h av e to u se an e x pre ssi o n l i k e

q4.v2().v1()

T h i s i s h ardl y co m pact o r i ntu i ti v e . F o rtu nate l y , i t i s po ssi bl e to w ri te re cu rsi v e te m pl ate s th at e f f i ci e ntl y re tri e v e th e v al u e s and ty pe s o f f i e l ds i n a re cu rsi v e du o .

L e t' s f i rst l o o k at th e co de f o r a ty pe f u ncti o n DuoT to re tri e v e th e nth ty pe o f a re cu rsi v e du o (y o u can f i nd th e co de i n tuples/duo3.hpp). T h e g e ne ri c de f i ni ti o n

// primary template for type of Nth field of (duo) T template <int N, typename T> class DuoT { public: typedef void ResultT; // in general, the result type is void

Page 456: CPlusPlus Templates The Complete Guide

};

e nsu re s th at th e re su l t ty pe i s void f o r no n-Duos. F ai rl y si m pl e parti al spe ci al i z ati o ns tak e care o f re tri e v i ng th e ty pe s f ro m no nre cu rsi v e Duos:

// specialization for 1st field of a plain duo template <typename A, typename B> class DuoT <1, Duo<A,B> > { public: typedef A ResultT; }; // specialization for 2nd field of a plain duo template <typename A, typename B> class DuoT<2, Duo<A,B> > { public: typedef B ResultT; };

W i th th i s i n pl ace , th e nth ty pe o f a re cu rsi v e du o , i n g e ne ral , i s th e (n-1)th ty pe o f th e se co nd f i e l d:

// specialization for Nth field of a recursive duo template <int N, typename A, typename B, typename C> class DuoT<N, Duo<A, Duo<B,C> > > { public: typedef typename DuoT<N-1, Duo<B,C> >::ResultT ResultT; };

H o w e v e r, th e re q u e st f o r th e f i rst ty pe o f a re cu rsi v e du o e nds th e re cu rsi o n:

// specialization for 1st field of a recursive duo template <typename A, typename B, typename C> class DuoT<1, Duo<A, Duo<B,C> > > { public: typedef A ResultT; };

No te th at th e case f o r th e se co nd ty pe o f th e re cu rsi v e du o al so ne e ds a parti al spe ci al i z ati o n to av o i d am bi g u i ty w i th th e no nre cu rsi v e case :

// specialization for 2nd field of a recursive duo template<typename A, typename B, typename C> class DuoT<2, Duo<A, Duo<B, C> > > { public: typedef B ResultT; };

T h i s i s ce rtai nl y no t th e o nl y w ay to i m pl e m e nt th e DuoT te m pl ate . T h e i nte re ste d re ade r co u l d, f o r e x am pl e , try to l e v e rag e th e IfThenElse te m pl ate (se e S e cti o n

Page 457: CPlusPlus Templates The Complete Guide

1 5 .2 .4 o n pag e 2 7 2 ) to ach i e v e an e q u i v al e nt e f f e ct.

21.2.3 Value of Fields

E x tracti ng th e nth v al u e (as an l v al u e ) f ro m a re cu rsi v e du o i s o nl y sl i g h tl y m o re co m pl e x th an e x tracti ng th e co rre spo ndi ng ty pe . T h e i nte rf ace w e i nte nd to ach i e v e i s th e f o rm val<N>(duo). H o w e v e r, w e ne e d a h e l pe r cl ass te m pl ate DuoValue to i m pl e m e nt i t be cau se o nl y cl ass te m pl ate s can be parti al l y spe ci al i z e d, and parti al spe ci al i z ati o n al l o w s u s to re cu r to th e de si re d v al u e m o re e f f i ci e ntl y . H e re i s h o w th e val() f u ncti o ns de l e g ate th e i r task :

// tuples/duo5.hpp #include "typeop.hpp" // return Nth value of variable duo template <int N, typename A, typename B> inline typename TypeOp<typename DuoT<N, Duo<A, B> >::ResultT>::RefT val(Duo<A, B>& d) { return DuoValue<N, Duo<A, B> >::get(d); } // return Nth value of constant duo template <int N, typename A, typename B> inline typename TypeOp<typename DuoT<N, Duo<A, B> >::ResultT>::RefConstT val(Duo<A, B> const& d) { return DuoValue<N, Duo<A, B> >::get(d); }

T h e DuoT te m pl ate al re ady pro v e s i tse l f u se f u l to de cl are th e re tu rn ty pe o f th e val() f u ncti o ns. W e al so u se d th e TypeOp ty pe f u ncti o n de v e l o pe d i n S e cti o n 1 5 .2 .3 o n pag e 2 6 9 to cre ate a re f e re nce ty pe re l i abl y , e v e n i f th e f i e l d ty pe i s i tse l f al re ady a re f e re nce .

T h e f o l l o w i ng co m pl e te i m pl e m e ntati o n o f DuoValue cl e arl y paral l e l s o u r pre v i o u s di scu ssi o n o f DuoT (th e ro l e o f e ach e l e m e nt o f th e i m pl e m e ntati o n i s di scu sse d ne x t):

// tuples/duo4.hpp #include "typeop.hpp" // primary template for value of Nth field of (duo) T template <int N, typename T> class DuoValue { public: static void get(T&) { // in general, we have no value

Page 458: CPlusPlus Templates The Complete Guide

} static void get(T const&) { } }; // specialization for 1st field of a plain duo template <typename A, typename B> class DuoValue<1, Duo<A, B> > { public: static A& get(Duo<A, B> &d) { return d.v1(); } static A const& get(Duo<A, B> const &d) { return d.v1(); } }; // specialization for 2nd field of a plain duo template <typename A, typename B> class DuoValue<2, Duo<A, B> > { public: static B& get(Duo<A, B> &d) { return d.v2(); } static B const& get(Duo<A, B> const &d) { return d.v2(); } }; // specialization for Nth field of recursive duo template <int N, typename A, typename B, typename C> struct DuoValue<N, Duo<A, Duo<B,C> > > { static typename TypeOp<typename DuoT<N-1, Duo<B,C> >::ResultT>::RefT get(Duo<A, Duo<B,C> > &d) { return DuoValue<N-1, Duo<B,C> >::get(d.v2()); } static typename TypeOp<typename DuoT<N-1, Duo<B,C> >::ResultT>::RefConstT get(Duo<A, Duo<B,C> > const &d) { return DuoValue<N-1, Duo<B,C> >::get(d.v2()); } }; // specialization for 1st field of recursive duo template <typename A, typename B, typename C> class DuoValue<1, Duo<A, Duo<B,C> > > { public: static A& get(Duo<A, Duo<B,C> > &d) { return d.v1(); } static A const& get(Duo<A, Duo<B,C> > const &d) { return d.v1(); } }; // specialization for 2nd field of recursive duo template <typename A, typename B, typename C> class DuoValue<2, Duo<A, Duo<B,C> > > { public:

Page 459: CPlusPlus Templates The Complete Guide

static B& get(Duo<A, Duo<B,C> > &d) { return d.v2().v1(); } static B const& get(Duo<A, Duo<B,C> > const &d) { return d.v2().v1(); } };

A s w i th DuoT, w e pro v i de a g e ne ri c de f i ni ti o n o f DuoValue th at m aps to f u ncti o ns th at re tu rn void. B e cau se f u ncti o n te m pl ate s can re tu rn void e x pre ssi o ns, th i s m ak e s th e appl i cati o n o f val() to no ndu o s o r o u t-o f -rang e v al u e s o f N v al i d (al th o u g h u se l e ss, bu t i t can si m pl i f y th e i m pl e m e ntati o n o f ce rtai n te m pl ate s):

// primary template for value of Nth field of (duo) T template <int N, typename T> class DuoValue { public: static void get(T&) { // in general, we have no value } static void get(T const&) { } };

A s be f o re , w e f i rst spe ci al i z e f o r no nre cu rsi v e du o s:

// specialization for 1st field of a plain duo template <typename A, typename B> class DuoValue<1, Duo<A, B> > { public: static A& get(Duo<A, B> &d) { return d.v1(); } static A const& get(Duo<A, B> const& d) { return d.v1(); } }; …

T h e n w e spe ci al i z e f o r re cu rsi v e du o s (ag ai n DuoT co m e s i n h andy ):

template <int N, typename A, typename B, typename C> class DuoValue<N, Duo<A, Duo<B, C> > > { public: static typename TypeOp<typename DuoT<N-1, Duo<B, C> >::ResultT>::RefT get(Duo<A, Duo<B, C> > &d) { return DuoValue<N-1, Duo<B, C> >::get(d.v2()); } … }; // specialization for 1st field of recursive duo

Page 460: CPlusPlus Templates The Complete Guide

template <typename A, typename B, typename C> class DuoValue<1, Duo<A, Duo<B, C> > > { public: static A& get(Duo<A, Duo<B, C> > &d) { return d.v1(); } … }; // specialization for 2nd field of recursive duo template <typename A, typename B, typename C> class DuoValue<2, Duo<A, Duo<B, C> > > { public: static B& get(Duo<A, Duo<B, C> > &d) { return d.v2().v1(); } … };

T h e f o l l o w i ng pro g ram sh o w s h o w to u se du o s:

// tuples/duo5.cpp #include "duo1.hpp" #include "duo2.hpp" #include "duo3.hpp" #include "duo4.hpp" #include "duo5.hpp" #include <iostream> int main() { // create and use simple duo Duo<bool,int> d; std::cout << d.v1() << std::endl; std::cout << val<1>(d) << std::endl; // create and use triple Duo<bool,Duo<int,float> > t; val<1>(t) = true; val<2>(t) = 42; val<3>(t) = 0.2; std::cout << val<1>(t) << std::endl; std::cout << val<2>(t) << std::endl; std::cout << val<3>(t) << std::endl; }

T h e cal l o f

val<3>(t)

e nds u p i n th e cal l o f

Page 461: CPlusPlus Templates The Complete Guide

t.v2().v2()

B e cau se th e re cu rsi o n i s u nw rappe d at co m pi l e ti m e du ri ng th e te m pl ate i nstanti ati o n pro ce ss and th e f u ncti o ns are si m pl e i nl i ne acce sso rs, th e se f aci l i ti e s e nd u p be i ng q u i te e f f i ci e nt. A g o o d co m pi l e r re du ce s th i s to th e sam e co de as a si m pl e stru ctu re f i e l d acce ss.

H o w e v e r, i t i s sti l l cu m be rso m e to de cl are and co nstru ct re cu rsi v e Duo o bj e cts. T h e ne x t se cti o n addre sse s th i s ch al l e ng e .

Page 462: CPlusPlus Templates The Complete Guide

21.3 Tuple Construction

T h e ne ste d stru ctu re o f re cu rsi v e du o s i s co nv e ni e nt to appl y te m pl ate m e tapro g ram m i ng te ch ni q u e s to th e m . H o w e v e r, f o r a h u m an pro g ram m e r i t i s m o re pl e asi ng to h av e a f l at i nte rf ace to th i s stru ctu re . T o o btai n th i s, w e can de f i ne a re cu rsi v e Tuple te m pl ate w i th m any param e te rs and h av e i t be a de ri v ati o n f ro m a re cu rsi v e du o ty pe o f appro pri ate si z e . W e sh o w th e co de h e re f o r tu pl e s u p to f i v e f i e l ds, bu t i t i s no t si g ni f i cantl y h arde r to pro v i de f o r a do z e n f i e l ds o r so . Y o u can f i nd th e co de i n tuples/tuple1.hpp.

T o al l o w f o r tu pl e s o f v ary i ng si z e s, w e h av e u nu se d ty pe param e te rs th at de f au l t to a nu l l ty pe , NullT , w h i ch w e de f i ne as a pl ace h o l de r f o r th at pu rpo se . W e u se NullT rath e r th an void be cau se w e w i l l cre ate param e te rs o f th at ty pe (void canno t be a param e te r ty pe ):

// type that represents unused type parameters class NullT { };

Tuple i s de f i ne d as a te m pl ate th at de ri v e s f ro m a Duo h av i ng o ne m o re ty pe param e te r w i th NullT de f i ne d:

// Tuple<> in general derives from Tuple<> with one more NullT template<typename P1, typename P2 = NullT, typename P3 = NullT, typename P4 = NullT, typename P5 = NullT> class Tuple : public Duo<P1, typename Tuple<P2,P3,P4,P5,NullT>::BaseT> { public: typedef Duo<P1, typename Tuple<P2,P3,P4,P5,NullT>::BaseT> BaseT; // constructors: Tuple() {} Tuple(TypeOp<P1>::RefConstT a1, TypeOp<P2>::RefConstT a2, TypeOp<P3>::RefConstT a3 = NullT(), TypeOp<P4>::RefConstT a4 = NullT(), TypeOp<P5>::RefConstT a5 = NullT()) : BaseT(a1, Tuple<P2,P3,P4,P5,NullT>(a2,a3,a4,a5)) { } };

No te th e sh i f ti ng patte rn w h e n passi ng th e param e te rs to th e re cu rsi v e ste p. B e cau se w e de ri v e f ro m a base ty pe th at de f i ne s m e m b e r ty pe s T1 and T2 , w e

[2 ]

Page 463: CPlusPlus Templates The Complete Guide

u se d te m pl ate param e te r nam e s o f th e f o rm Pn i nste ad o f th e u su al Tn. [2 ]

[2 ] A v e ry cu ri o u s l o o k u p ru l e i n C + + pre f e rs nam e s i nh e ri te d f ro m no nde pe nde nt base cl asse s o v e r te m pl ate param e te r nam e s. T h i s sh o u l d no t be a pro bl e m i n th i s case be cau se th e base cl ass i s de pe nde nt, bu t so m e co m pi l e rs sti l l g e t th i s w ro ng at th e ti m e o f th i s w ri ti ng .

W e ne e d a parti al spe ci al i z ati o n to e nd th i s re cu rsi o n w i th th e de ri v ati o n f ro m a no nre cu rsi v e du o :

// specialization to end deriving recursion template <typename P1, typename P2> class Tuple<P1,P2,NullT,NullT,NullT> : public Duo<P1,P2> { public: typedef Duo<P1,P2> BaseT; Tuple() {} Tuple(TypeOp<P1>::RefConstT a1, TypeOp<P2>::RefConstT a2, TypeOp<NullT>::RefConstT = NullT(), TypeOp<NullT>::RefConstT = NullT(), TypeOp<NullT>::RefConstT = NullT()) : BaseT(a1, a2) { } };

A de cl arati o n su ch as

Tuple<bool,int,float,double> t4(true,42,13,1.95583);

e nds u p i n th e h i e rarch y sh o w n i n F i g u re 2 1 .1 .

Figure 21.1. Type of Tuple<bool,int,float,double>

T h e o th e r spe ci al i z ati o n tak e s care o f th e case w h e n th e tu pl e i s re al l y a

Page 464: CPlusPlus Templates The Complete Guide

si ng l e to n:

// specialization for singletons template <typename P1> class Tuple<P1,NullT,NullT,NullT,NullT> : public Duo<P1,void> { public: typedef Duo<P1,void> BaseT; Tuple() {} Tuple(TypeOp<P1>::RefConstT a1, TypeOp<NullT>::RefConstT = NullT(), TypeOp<NullT>::RefConstT = NullT(), TypeOp<NullT>::RefConstT = NullT(), TypeOp<NullT>::RefConstT = NullT()) : BaseT(a1) { } };

F i nal l y , i t i s natu ral to de si re f u ncti o ns l i k e make_duo() i n S e cti o n 2 1 .1 o n pag e 3 9 6 to de du ce th e te m pl ate param e te rs au to m ati cal l y . U nf o rtu nate l y , a di f f e re nt f u ncti o n te m pl ate de cl arati o n i s ne e de d f o r e ach tu pl e si z e th at m u st be su ppo rte d be cau se f u ncti o n te m pl ate s canno t h av e de f au l t te m pl ate arg u m e nts, [3 ] no r are th e i r de f au l t f u ncti o n cal l arg u m e nts co nsi de re d i n th e te m pl ate param e te r de du cti o n pro ce ss. T h e f u ncti o ns are de f i ne d as f o l l o w s:

[3 ] A re v i si o n o f th e C + + standard w i l l m o st l i k e l y re m o v e th i s l i m i tati o n (se e S e cti o n 1 3 .3 o n pag e 2 0 7 ).

// convenience function for 1 argument template <typename T1> inline Tuple<T1> make_tuple(T1 const &a1) { return Tuple<T1>(a1); } // convenience function for 2 arguments template <typename T1, typename T2> inline Tuple<T1,T2> make_tuple(T1 const &a1, T2 const &a2) { return Tuple<T1,T2>(a1,a2); } // convenience function for 3 arguments template <typename T1, typename T2, typename T3> inline Tuple<T1,T2,T3> make_tuple(T1 const &a1, T2 const &a2, T3 const &a3) { return Tuple<T1,T2,T3>(a1,a2,a3); } // convenience function for 4 arguments template <typename T1, typename T2, typename T3, typename T4> inline

Page 465: CPlusPlus Templates The Complete Guide

Tuple<T1,T2,T3,T4> make_tuple(T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4) { return Tuple<T1,T2,T3,T4>(a1,a2,a3,a4); } // convenience function for 5 arguments template <typename T1, typename T2, typename T3, typename T4, typename T5> inline Tuple<T1,T2,T3,T4,T5> make_tuple(T1 const &a1, T2 const &a2, T3 const &a3, T4 const &a4, T5 const &a5) { return Tuple<T1,T2,T3,T4,T5>(a1,a2,a3,a4,a5); }

T h e f o l l o w i ng pro g ram sh o w s h o w to u se Tuples:

// tuples/tuple1.cpp #include "tuple1.hpp" #include <iostream> int main() { // create and use tuple with only one field Tuple<int> t1; val<1>(t1) += 42; std::cout << t1.v1() << std::endl; // create and use duo Tuple<bool,int> t2; std::cout << val<1>(t2) << ", "; std::cout << t2.v1() << std::endl; // create and use triple Tuple<bool,int,double> t3; val<1>(t3) = true; val<2>(t3) = 42; val<3>(t3) = 0.2; std::cout << val<1>(t3) << ", "; std::cout << val<2>(t3) << ", "; std::cout << val<3>(t3) << std::endl; t3 = make_tuple(false, 23, 13.13); std::cout << val<1>(t3) << ", "; std::cout << val<2>(t3) << ", "; std::cout << val<3>(t3) << std::endl; // create and use quadruple Tuple<bool,int,float,double> t4(true,42,13,1.95583); std::cout << val<4>(t4) << std::endl; std::cout << t4.v2().v2().v2() << std::endl; }

Page 466: CPlusPlus Templates The Complete Guide

A n i ndu stri al -stre ng th i m pl e m e ntati o n w o u l d co m pl e te th e co de w e pre se nte d so f ar w i th v ari o u s e x te nsi o ns. F o r e x am pl e , w e co u l d de f i ne assi g nm e nt o pe rato r te m pl ate s to f aci l i tate tu pl e co nv e rsi o ns; o th e rw i se , th e ty pe s h av e to m atch e x actl y :

Tuple<bool,int,float> t3; t3 = make_tuple(false, 23, 13.13); // ERROR: 13.13 has type double

Page 467: CPlusPlus Templates The Complete Guide

21.4 Afternotes

T u pl e co nstru cti o n i s o ne o f th o se te m pl ate appl i cati o ns th at appe ars to h av e be e n i nde pe nde ntl y atte m pte d by m any pro g ram m e rs. T h e de tai l s o f th e se atte m pts v ary w i de l y , bu t m any are base d o n th e i de a o f a re cu rsi v e pai r stru ctu re (su ch as o u r re cu rsi v e du o s). O ne i nte re sti ng al te rnati v e w as de v e l o pe d by A ndre i A l e x andre scu i n [A l e x andre scu D e si g n]. H e cl e anl y se parate s th e l i st o f ty pe s f ro m th e l i st o f f i e l ds i n th e tu pl e . T h i s l e ads to th e co nce pt o f a t yp e l i s t th at h as v ari o u s appl i cati o ns o f i ts o w n (o ne o f w h i ch i s th e co nstru cti o n o f a tu pl e w i th th e e ncapsu l ate d ty pe s).

S e cti o n 1 3 .1 3 o n pag e 2 2 2 di scu sse s th e co nce pt o f t e m p l a t e l i s t p a r a m e t e r s , w h i ch are a l ang u ag e e x te nsi o n th at m ak e s th e i m pl e m e ntati o n o f tu pl e s al m o st tri v i al .

Page 468: CPlusPlus Templates The Complete Guide

Chapter 22. Function Objects and Callbacks

A f unc t i on ob j e c t (al so cal l e d a f unc t or ) i s any o bj e ct th at can be cal l e d u si ng th e f unc t i on c a l l s ynt a x . In th e C pro g ram m i ng l ang u ag e , th re e k i nds o f e nti ti e s can l e ad to sy ntax th at l o o k s l i k e a f u ncti o n cal l : f u ncti o ns, f u ncti o n-l i k e m acro s, and po i nte rs to f u ncti o ns. B e cau se f u ncti o ns and m acro s are no t o bj e cts, th i s i m pl i e s th at o nl y po i nte rs to f u ncti o ns are av ai l abl e as f u ncto rs i n C . In C + + , addi ti o nal po ssi bi l i ti e s are adde d: T h e f unc t i on c a l l op e r a t or can be o v e rl o ade d f o r cl ass ty pe s, a co nce pt o f re f e re nce s to f u ncti o ns e x i sts, and m e m be r f u ncti o ns and po i nte r-to -m e m be r f u ncti o ns h av e a cal l sy ntax o f th e i r o w n. No t al l o f th e se co nce pts are e q u al l y u se f u l , bu t th e co m bi nati o n o f th e co nce pt o f a f u ncto r w i th th e co m pi l e -ti m e param e te ri z ati o n o f f e re d by te m pl ate s l e ads to po w e rf u l pro g ram m i ng te ch ni q u e s.

B e si de s de v e l o pi ng f u ncto r ty pe s, th i s ch apte r al so de l v e s i nto so m e u sag e i di o m s f o r f u ncto rs. Ne arl y al l u se s e nd u p be i ng a f o rm o f c a l l b a c k : T h e cl i e nt o f a l i brary w ants th at l i brary to cal l back so m e f u ncti o n o f th e cl i e nt co de . T h e cl assi c e x am pl e i s a so rti ng ro u ti ne th at ne e ds a f u ncti o n to co m pare tw o e l e m e nts i n th e se t be i ng so rte d. T h e co m pari so n ro u ti ne i s passe d as a f u ncto r i n th i s case . T radi ti o nal l y , th e te rm c a l l b a c k h as be e n re se rv e d f o r f u ncto rs th at are passe d as f u ncti o n cal l arg u m e nts (as o ppo se d to , f o r e x am pl e , te m pl ate arg u m e nts), and w e m ai ntai n th i s tradi ti o n.

T h e te rm s f unc t i on ob j e c t and f unc t or are u nf o rtu nate l y a l i ttl e f u z z y i n th e se nse th at di f f e re nt m e m b e rs o f th e C + + pro g ram m i ng co m m u ni ty m ay g i v e sl i g h tl y di f f e re nt m e ani ng s to th e se te rm s. A co m m o n v ari ati o n o f th e de f i ni ti o n w e h av e g i v e n i s to i ncl u de o nl y o bj e cts o f cl ass ty pe s i n th e f u ncto r o r f u ncti o n o bj e ct co nce pt; f u ncti o n po i nte rs are th e n e x cl u de d. In addi ti o n, i t i s no t u nco m m o n to re ad o r h e ar di scu ssi o ns re f e rri ng to th e cl ass t yp e o f a f u ncti o n o bj e ct as a " f u ncti o n o bj e ct." In o th e r w o rds, th e ph rase " cl ass o f f u ncti o n o bj e cts so and so … " i s sh o rte ne d to " f u ncti o n o bj e cts so and so … ." A l th o u g h w e so m e ti m e s h andl e th i s te rm i no l o g y so m e w h at sl o ppi l y i n o u r o w n dai l y w o rk , w e h av e m ade i t a po i nt to sti ck to o u r i ni ti al de f i ni ti o ns i n th i s ch apte r.

B e f o re di g g i ng i nto th e u se o f te m pl ate s to i m pl e m e nt u se f u l f u ncto rs, w e di scu ss so m e pro pe rti e s o f f u ncti o n cal l s th at m o ti v ate so m e o f th e adv antag e s o f te m pl ate -base d f u ncto rs.

Page 469: CPlusPlus Templates The Complete Guide

22.1 Direct, Indirect, and Inline Calls

T y pi cal l y , w h e n a C o r C + + co m pi l e r e nco u nte rs th e de f i ni ti o n o f a no ni nl i ne f u ncti o n, i t g e ne rate s and sto re s m ach i ne co de f o r th at f u ncti o n i n an o bj e ct f i l e . It al so cre ate s a nam e asso ci ate d w i th th e m ach i ne co de ; i n C , th i s nam e i s ty pi cal l y th e f u ncti o n nam e i tse l f , bu t i n C + + th e nam e i s u su al l y e x te nde d w i th an e nco di ng o f th e param e te r ty pe s to al l o w f o r u ni q u e nam e s e v e n w h e n a f u ncti o n i s o v e rl o ade d (th e re su l ti ng nam e i s u su al l y cal l e d a m a ng l e d na m e , al th o u g h th e te rm de c or a t e d na m e i s al so u se d). S i m i l arl y , w h e n th e co m pi l e r e nco u nte rs a cal l si te l i k e

f();

i t g e ne rate s m ach i ne co de f o r a cal l to a f u ncti o n o f th at ty pe . F o r m o st m ach i ne l ang u ag e s, th e cal l i nstru cti o n i tse l f ne ce ssi tate s th e starti ng addre ss o f th e ro u ti ne . T h i s addre ss can be part o f th e i nstru cti o n (i n w h i ch case th e i nstru cti o n i s cal l e d a di r e c t c a l l ), o r i t m ay re si de so m e w h e re i n m e m o ry o r i n a m ach i ne re g i ste r (i ndi r e c t c a l l ). A l m o st al l m o de rn co m pu te r arch i te ctu re s pro v i de bo th ty pe s o f ro u ti ne cal l i ng i nstru cti o ns, bu t (f o r re aso ns th at are be y o nd th e sco pe o f th i s bo o k ) di re ct cal l s are e x e cu te d m o re e f f i ci e ntl y th an i ndi re ct cal l s. In f act, as co m pu te r arch i te ctu re s g e t m o re so ph i sti cate d, i t appe ars th at th e pe rf o rm ance g ap be tw e e n di re ct cal l s and i ndi re ct cal l s i ncre ase s. H e nce , co m pi l e rs g e ne ral l y atte m pt to g e ne rate a di re ct cal l i nstru cti o n w h e n po ssi bl e .

In g e ne ral , a co m pi l e r do e s no t k no w at w h i ch addre ss a f u ncti o n i s l o cate d (th e f u ncti o n co u l d, f o r e x am pl e , be i n ano th e r transl ati o n u ni t). H o w e v e r, i f th e co m pi l e r k no w s th e nam e o f th e f u ncti o n, i t g e ne rate s a di re ct cal l i nstru cti o n w i th a du m m y addre ss. In addi ti o n, i t g e ne rate s an e ntry i n th e g e ne rate d o bj e ct f i l e di re cti ng th e l i nk e r to u pdate th at i nstru cti o n to po i nt to th e addre ss o f a f u ncti o n w i th th e g i v e n nam e . B e cau se th e l i nk e r se e s th e o bj e ct f i l e s cre ate d f ro m al l th e transl ati o n u ni ts, i t k no w s th e cal l si te s as w e l l as th e de f i ni ti o n si te s and h e nce i s abl e to patch u p al l th e di re ct cal l si te s. [1]

[1] T h e l i nk e r pe rf o rm s a si m i l ar ro l e f o r acce sse s to nam e space sco pe v ari abl e s, f o r e x am pl e .

U nf o rtu nate l y , w h e n th e nam e o f th e f u ncti o n i s no t av ai l abl e , an i ndi re ct cal l m u st be u se d. T h i s i s u su al l y th e case f o r cal l s th ro u g h po i nte rs to f u ncti o ns:

void foo (void (*pf)()) { pf(); // indirect call through pointer to function pf

Page 470: CPlusPlus Templates The Complete Guide

}

In th i s e x am pl e i t i s, i n g e ne ral , no t po ssi bl e f o r a co m pi l e r to k no w to w h i ch f u ncti o n th e param e te r pf po i nts (af te r al l , i t i s m o st l i k e l y di f f e re nt f o r a di f f e re nt i nv o cati o n o f foo()). H e nce , th e te ch ni q u e o f h av i ng th e l i nk e r m atch nam e s do e s no t w o rk . T h e cal l de sti nati o n i s no t k no w n u nti l th e co de i s actu al l y e x e cu te d.

A l th o u g h a m o de rn co m pu te r can o f te n e x e cu te a di re ct cal l i nstru cti o n abo u t as q u i ck l y as o th e r co m m o n i nstru cti o ns (f o r e x am pl e , an i nstru cti o n to add tw o i nte g e rs), f u ncti o n cal l s can sti l l be a se ri o u s pe rf o rm ance i m pe di m e nt. T h e f o l l o w i ng e x am pl e sh o w s th i s:

int f1(int const & r) { return ++(int&)r; // not reasonable, but legal } int f2(int const & r) { return r; } int f3() { return 42; } int foo() { int param = 0; int answer = 0; answer = f1(param); f2(param); f3(); return answer + param; }

F u ncti o n f1() tak e s a const int re f e re nce arg u m e nt. O rdi nari l y , th i s m e ans th at th e f u ncti o n do e s no t m o di f y th e o bj e ct th at i s passe d by re f e re nce . H o w e v e r, i f th e o bj e ct passe d i n i s a m o di f i abl e v al u e , a C + + pro g ram can l e g al l y cast aw ay th e const pro pe rty and ch ang e th e v al u e o f th e o bj e ct any w ay . (Y o u co u l d arg u e th at th i s i s no t re aso nabl e ; h o w e v e r, i t i s standard C + + .) F u ncti o n f1() do e s e x actl y th i s. B e cau se o f th i s po ssi bi l i ty , a co m pi l e r th at o pti m i z e s g e ne rate d co de o n a pe rf u ncti o n basi s (and m o st co m pi l e rs do ) h as to assu m e th at e v e ry f u ncti o n th at tak e s re f e re nce s o r po i nte rs to o bj e cts m ay m o di f y th o se o bj e cts. No te th at i n g e ne ral a co m pi l e r se e s o nl y th e de c l a r a t i on o f a f u ncti o n be cau se th e de f i ni t i on (th e i m p l e m e nt a t i on) i s i n ano th e r transl ati o n u ni t.

In th e co de e x am pl e , m o st co m pi l e rs th e re f o re assu m e th at f2() can m o di f y

Page 471: CPlusPlus Templates The Complete Guide

answer to o (e v e n th o u g h i t do e s no t). In f act, th e co m pi l e r canno t e v e n assu m e th at f3() do e s no t m o di f y th e l o cal v ari abl e param. Inde e d, th e f u ncti o ns f1() and f2() h ad an o ppo rtu ni ty to sto re th e addre ss o f param i n a g l o bal l y acce ssi bl e po i nte r. F ro m th e l i m i te d pe rspe cti v e o f th e co m pi l e r, i t i s th e re f o re no t i m po ssi bl e f o r f3() to u se su ch a g l o bal l y acce ssi bl e po i nte r to m o di f y param. T h e ne t e f f e ct i s th at o rdi nary f u ncti o n cal l s co nf u se m o st co m pi l e rs re g ardi ng w h at h appe ne d to v ari o u s o bj e cts, f o rci ng th e m o f te n to sto re th e i r i nte rm e di ate v al u e s i n m ai n m e m o ry i nste ad o f k e e pi ng th e m i n f ast re g i ste rs and pre v e nti ng m any o pti m i z ati o ns th at i nv o l v e th e m o v e m e nt o f m ach i ne co de (th e f u ncti o n cal l o f te n f o rm s a b a r r i e r f o r co de m o ti o n).

A dv ance d C + + co m pi l ati o n sy ste m s e x i st th at are capabl e o f track i ng m any i nstance s o f su ch po te nti al a l i a s i ng (i n th e sco pe o f f1(), th e e x pre ssi o n r i s an al i as f o r th e o bj e ct nam e d param i n th e sco pe o f foo()). H o w e v e r, th i s abi l i ty co m e s at a pri ce : co m pi l ati o n spe e d, re so u rce u sag e , and co de re l i abi l i ty . P ro j e cts th at o th e rw i se bu i l d i n m i nu te s so m e ti m e s tak e h o u rs o r e v e n day s to be co m pi l e d (pro v i de d th e ne ce ssary g i g aby te s o f m e m o ry are av ai l abl e to th e co m pi l e r). F u rth e rm o re , su ch co m pi l ati o n sy ste m s are ty pi cal l y m u ch m o re co m pl e x and are th e re f o re m o re o f te n pro ne to g e ne rati ng w ro ng co de . E v e n w h e n a su pe ro pti m i z i ng co m pi l e r g e ne rate s co rre ct co de , th e so u rce co de m ay co ntai n u ni nte nde d v i o l ati o ns o f su btl e C and C + + al i asi ng ru l e s. [2 ] S o m e o f th e se v i o l ati o ns are f ai rl y h arm l e ss w i th o rdi nary o pti m i z e rs, bu t su pe ro pti m i z e rs m ay tu rn th e m i nto tru e bu g s.

[2 ] F o r e x am pl e , acce ssi ng an unsigned int th ro u g h a po i nte r to a re g u l ar (si g ne d) int i s su ch an e rro r.

H o w e v e r, o rdi nary o pti m i z e rs can be h e l pe d tre m e ndo u sl y by th e pro ce ss o f i nl i ni ng . S u ppo se f1(), f2() , and f3() are de cl are d i nl i ne . T h e co m pi l e r can th e n transf o rm th e co de o f foo() to so m e th i ng e sse nti al l y e q u i v al e nt to

int foo'() { int param = 0; int answer = 0; answer = ++(int&)param; return answer + param; }

w h i ch a v e ry o rdi nary o pti m i z e r can tu rn i nto

int foo''() { return 2; }

Page 472: CPlusPlus Templates The Complete Guide

T h i s i l l u strate s th at th e be ne f i t o f i nl i ni ng l i e s no t o nl y i n th e av o i dance o f e x e cu ti ng m ach i ne co de f o r a cal l i ng se q u e nce bu t al so (and o f te n m o re i m po rtant) i n m ak i ng v i si bl e to an o pti m i z e r w h at h appe ns to th e v ari abl e s passe d to th e f u ncti o n.

W h at do e s th i s h av e to do w i th te m pl ate s? W e l l , as w e se e l ate r, i t i s so m e ti m e s po ssi bl e u si ng te m pl ate -base d cal l back s to g e ne rate co de th at i nv o l v e s di re ct o r e v e n i nl i ne cal l s w h e n m o re tradi ti o nal cal l back s w o u l d re su l t i n i ndi re ct cal l s. T h e sav i ng s i n ru nni ng ti m e can be co nsi de rabl e .

Page 473: CPlusPlus Templates The Complete Guide

22.2 Pointers and References to Functions

C o nsi de r th e f o l l o w i ng f ai rl y tri v i al de f i ni ti o n o f a f u ncti o n foo():

extern "C++" void foo() throw() { }

T h e ty pe o f th i s f u ncti o n o u g h t to be " f u ncti o n w i th C + + l i nk ag e th at tak e s no arg u m e nts, re tu rns no v al u e , and do e s no t th ro w any e x ce pti o ns." F o r h i sto ri cal re aso ns, th e f o rm al de f i ni ti o n o f th e C + + l ang u ag e do e s no t actu al l y m ak e th e e x ce pti o n spe ci f i cati o n part o f a f u ncti o n ty pe . [3 ] H o w e v e r, th at m ay ch ang e i n th e f u tu re . It i s a g o o d i de a to m ak e su re th at w h e n y o u cre ate co de i n w h i ch f u ncti o n ty pe s m u st m atch , th e e x ce pti o n spe ci f i cati o ns al so m atch . Na m e l i nk a g e (u su al l y f o r "C" and "C++") i s pro pe rl y a part o f th e ty pe sy ste m , bu t so m e C + + i m pl e m e ntati o ns are a l i ttl e l ax i n e nf o rci ng i t. S pe ci f i cal l y , th e y al l o w a po i nte r to a f u ncti o n w i th C l i nk ag e to be assi g ne d to a po i nte r to a f u ncti o n w i th C + + l i nk ag e and v i ce v e rsa. T h i s i s a co nse q u e nce o f th e f act th at, o n m o st pl atf o rm s, cal l i ng co nv e nti o ns f o r C and C + + f u ncti o ns are i de nti cal as f ar as th e co m m o n su bse t o f param e te r and re tu rn ty pe s i s co nce rne d.

[3 ] T h e h i sto ri cal o ri g i n o f th i s i s no t cl e ar, and th e C + + standard i s so m e w h at i nco nsi ste nt i n th i s are a.

In m o st co nte x ts, th e e x pre ssi o n foo u nde rg o e s an i m pl i ci t co nv e rsi o n to a po i nte r to th e f u ncti o n foo(). No te th at foo i tse l f do e s no t de no te th e po i nte r, j u st as th e e x pre ssi o n ia af te r th e de cl arati o n

int ia[10];

do e s no t de no te a po i nte r to th e array (o r to th e f i rst e l e m e nt o f th e array ). T h e i m pl i ci t co nv e rsi o n f ro m a f u ncti o n (o r array ) to a po i nte r i s o f te n cal l e d de c a y. T o i l l u strate th i s, w e can w ri te th e f o l l o w i ng co m pl e te C + + pro g ram :

// functors/funcptr.cpp #include <iostream> #include <typeinfo> void foo() { std::cout << "foo() called" << std::endl; }

Page 474: CPlusPlus Templates The Complete Guide

typedef void FooT(); // FooT is a function type, // the same type as that of function foo() int main() { foo(); // direct call // print types of foo and FooT std::cout << "Types of foo: " << typeid(foo).name() << '\n'; std::cout << "Types of FooT: " << typeid(FooT).name() << '\n'; FooT* pf = foo; // implicit conversion (decay) pf(); // indirect call through pointer (*pf)(); // equivalent to pf() // print type of pf std::cout << "Types of pf: " << typeid(pf).name() << '\n'; FooT& rf = foo; // no implicit conversion rf(); // indirect call through reference // print type of rf std::cout << "Types of rf: " << typeid(rf).name() << '\n'; }

T h i s e x am pl e sh o w s v ari o u s u se s o f f u ncti o n ty pe s, i ncl u di ng so m e u nu su al o ne s.

T h e e x am pl e u se s th e typeid o pe rato r, w h i ch re tu rns a stati c ty pe std::type_info, f o r w h i ch name() sh o w s th e ty pe s o f so m e e x pre ssi o ns (se e S e cti o n 5 .6 o n pag e 5 8 ). No ty pe de cay o ccu rs w h e n typeid i s appl i e d to a f u ncti o n ty pe .

H e re i s th e o u tpu t pro du ce d by o ne o f o u r C + + i m pl e m e ntati o ns:

foo() called Types of foo: void () Types of FooT: void () foo() called foo() called Types of pf: FooT * foo() called Types of rf: void ()

A s y o u can se e , th i s i m pl e m e ntati o n k e e ps ty pe de f nam e s i n th e stri ng re tu rne d by name() (f o r e x am pl e , FooT * i nste ad o f i ts e x pande d f o rm void (*)()), bu t th i s i s ce rtai nl y no t a l ang u ag e re q u i re m e nt.

T h i s e x am pl e al so sh o w s th at re f e re nce s to f u ncti o ns e x i st as a l ang u ag e co nce pt, bu t po i nte rs to f u ncti o ns are al m o st al w ay s u se d i nste ad (and to av o i d co nf u si o n, i t i s pro babl y be st to k e e p w i th th i s u se ). O bse rv e th at th e e x pre ssi o n foo i s i n

Page 475: CPlusPlus Templates The Complete Guide

f act a so -cal l e d l v a l ue be cau se i t can be bo u nd to a re f e re nce to a no n-const ty pe . H o w e v e r, i t i s no t po ssi bl e to m o di f y th at l v al u e .

No te th at th e nam e o f a po i nte r to a f u ncti o n (l i k e pf) o r th e nam e o f a re f e re nce to a f u ncti o n (l i k e rf) can be u se d i n a f u ncti o n cal l e x actl y l i k e th e nam e o f a f u ncti o n i tse l f . H e nce , a p oi nt e r t o a f unc t i on i s a f unc t or —an o bj e ct th at can be u se d i n pl ace o f a f u ncti o n nam e i n f u ncti o n cal l sy ntax . O n th e o th e r h and, be cau se a re f e re nce i s no t an o bj e ct, a re f e re nce to a f u ncti o n i s no t a f u ncto r. R e cal l f ro m o u r di scu ssi o n o f di re ct and i ndi re ct cal l s th at be h i nd th e se i de nti cal no tati o ns can be co nsi de rabl y di f f e re nt pe rf o rm ance ch aracte ri sti cs.

Page 476: CPlusPlus Templates The Complete Guide

22.3 Pointer-to-Member Functions

T o u nde rstand w h y a di sti ncti o n i s m ade be tw e e n po i nte rs to o rdi nary f u ncti o ns and po i nte rs to m e m be r f u ncti o ns, i t i s u se f u l to stu dy th e ty pi cal C + + i m pl e m e ntati o n o f a cal l to a m e m be r f u ncti o n. S u ch a cal l co u l d tak e th e f o rm p->mf() o r a cl o se v ari ati o n o f th i s sy ntax . H e re , p i s a po i nte r to an o bj e ct o r to a su bo bj e ct. It i s passe d i n so m e f o rm as a h i dde n param e te r to mf() , w h e re i t i s k no w n as th e this po i nte r.

T h e m e m b e r f u ncti o n mf() m ay h av e be e n de f i ne d f o r th e su bo bj e ct po i nte d to by p, o r i t m ay be i nh e ri te d by th e su bo bj e ct. F o r e x am pl e :

class B1 { private: int b1; public: void mf1(); }; void B1::mf1() { std::cout << "b1="<<b1<<std::endl; }

A s a m e m b e r f u ncti o n, mf1() e x pe cts to be cal l e d f o r an o bj e ct o f ty pe B1. T h u s, this re f e rs to to an o bj e ct o f ty pe B1.

L e t' s add so m e m o re co de to th i s:

class B2 { private: int b2; public: void mf2(); }; void B1::mf2() { std::cout << "b2="<<b2<<std::endl; }

T h e m e m b e r mf2() si m i l arl y e x pe cts th e h i dde n param e te r this to po i nt to a B2 su bo bj e ct.

No w l e t' s de ri v e a cl ass f ro m bo th B1 and B2:

Page 477: CPlusPlus Templates The Complete Guide

class D: public B1, public B2 { private: int d; };

W i th th i s de cl arati o n, an o bj e ct o f ty pe D can be h av e as an o bj e ct o f ty pe B1 o r an o bj e ct o f ty pe B2. F o r th i s to w o rk , a D o bj e ct co ntai ns bo th a B1 su bo bj e ct and a B2 su bo bj e ct. O n ne arl y al l 3 2 -bi t i m pl e m e ntati o ns w e k no w o f to day , a D o bj e ct w i l l be o rg ani z e d as sh o w n i n F i g u re 2 2 .1 . T h at i s, i f th e si z e o f th e int m e m be rs i s 4 by te s, m e m b e r b1 h as th e addre ss o f this, m e m be r b2 h as th e addre ss o f this pl u s 4 by te s, and m e m be r d h as th e addre ss o f this pl u s 8 by te s. No te h o w th e B1 su bo bj e ct sh are s i ts o ri g i n w i th th e o ri g i n o f th e D su bo bj e ct, bu t th e B2 su bo bj e ct do e s no t.

Figure 22.1. Typic a l orga n iz a t ion of t ype D

C o nsi de r no w th e f o l l o w i ng e l e m e ntary m e m be r f u ncti o n cal l s:

int main() { D obj; obj.mf1(); obj.mf2(); }

T h e cal l obj.mf2() re q u i re s th e addre ss o f th e su bo bj e ct o f ty pe B2 i n obj to be passe d to mf2(). A ssu m i ng th e ty pi cal i m pl e m e ntati o n de scri be d, th i s i s th e addre ss o f obj pl u s 4 by te s. It i s no t at al l h ard f o r a C + + co m pi l e r to g e ne rate co de to pe rf o rm th i s adj u stm e nt. No te th at f o r th e cal l to mf1(), th i s adj u stm e nt sh o u l d no t be do ne be cau se th e addre ss o f obj i s al so th e addre ss o f th e su bo bj e ct o f ty pe B1 w i th i n obj.

H o w e v e r, w i th po i nte r-to -m e m be r f u ncti o ns th e co m pi l e r do e s no t k no w w h at adj u stm e nt i s ne e de d. T o se e th i s, re pl ace th e pre v i o u s main() ro u ti ne w i th th e

Page 478: CPlusPlus Templates The Complete Guide

f o l l o w i ng :

void call_memfun (D obj, void D::*pmf()) { obj.*pmf(); } int main() { D obj; call_memfun(obj, &D::mf1); call_memfun(obj, &D::mf2); }

T o m ak e th e si tu ati o n e v e n m o re o paq u e to a C + + co m pi l e r, th e call_memfun() and main() m ay be pl ace d i n di f f e re nt transl ati o n u ni ts.

T h e co ncl u si o n i s th at i n addi ti o n to th e addre ss o f th e f u ncti o n, a po i nte r to a m e m be r f u ncti o n al so ne e ds to track th e this po i nte r adj u stm e nt ne e de d f o r a parti cu l ar m e m be r f u ncti o n. T h i s adj u stm e nt m ay ch ang e w h e n a po i nte r-to -m e m be r f u ncti o n i s caste d. W i th o u r e x am pl e :

void D::*pmf_a() = &D::mf2; // adjustment of +4 recorded void B2::*pmf_b() = (void (B2::*)())pmf_a; // adjustment changed to 0

T h e m ai n pu rpo se o f th i s di scu ssi o n i s to i l l u strate th e i ntri nsi c di f f e re nce be tw e e n a po i nte r to a m e m be r f u ncti o n and a po i nte r to a f u ncti o n. H o w e v e r, th e o u tl i ne i s no t su f f i ci e nt w h e n i t co m e s to v i rtu al f u ncti o ns, and i n practi ce m any i m pl e m e ntati o ns u se a th re e -w o rd stru ctu re f o r po i nte rs to m e m be r f u ncti o ns:

1. T h e a d d r e s s o f t h e m e m b e r f u n c t i o n , o r NULL i f i t i s a v i r t u a l f u n c t i o n 2 . T h e r e q u i r e d this a d j u s t m e n t 3 . A v i r t u a l f u n c t i o n i n d e x

T h e de tai l s are be y o nd th e sco pe o f th i s bo o k . If y o u ' re cu ri o u s abo u t th i s to pi c, a g o o d i ntro du cti o n can be f o u nd i n S tan L i ppm an' s I ns i de t h e C + + O b j e c t M ode l (se e [L i ppm anO bj M o d]). T h e re y o u w i l l al so f i nd th at po i nte rs to data m e m b e rs are ty pi cal l y no t po i nte rs at al l , bu t th e o f f se ts ne e de d to g e t f ro m this to a g i v e n f i e l d (a si ng l e w o rd o f sto rag e i s su f f i ci e nt f o r th e i r re pre se ntati o n).

F i nal l y , no te h o w " g e tti ng to a m e m be r f u ncti o n th ro u g h a po i nte r-to -m e m be r f u ncti o n" i s re al l y a bi nary o pe rati o n i nv o l v i ng no t o nl y th e p oi nt e r bu t al so th e ob j e c t to w h i ch th e po i nte r i s appl i e d. H e nce , spe ci al po i nte r-to -m e m be r de re f e re nci ng o pe rato rs .* and ->* w e re i ntro du ce d i nto th e l ang u ag e :

Page 479: CPlusPlus Templates The Complete Guide

obj.*pmf(… ) // call member function, to which pmf refers, for obj ptr->*pmf(… ) // call member function, to which pmf refers, for object, // to which ptr refers

In co ntrast, " g e tti ng to an o rdi nary f u ncti o n th ro u g h a po i nte r" i s a u nary o pe rati o n:

(*ptr)()

T h e de re f e re nci ng o pe rato r can be l e f t o u t be cau se i t i s i m pl i ci t i n th e f u ncti o n cal l o pe rato r. T h e pre v i o u s e x pre ssi o n i s th e re f o re u su al l y w ri tte n as

ptr()

T h e re i s no su ch i m pl i ci t f o rm f o r po i nte rs to m e m be r f u ncti o ns. [4 ] [4 ] T h e re i s al so no i m pl i ci t de cay o f a m e m be r f u ncti o n nam e su ch as MyType::print to a po i nte r to th at m e m be r. T h e am pe rsand i s al w ay s re q u i re d (f o r e x am pl e , &MyType::print). F o r o rdi nary f u ncti o ns, th e i m pl i ci t de cay o f f to &f i s w e l l k no w n.

Page 480: CPlusPlus Templates The Complete Guide

22.4 Class Type Functors

A l th o u g h po i nte rs to f u ncti o ns are f u ncto rs di re ctl y av ai l abl e i n th e l ang u ag e , th e re are m any si tu ati o ns i n w h i ch i t i s adv antag e o u s to u se a cl ass ty pe o bj e ct w i th an o v e rl o ade d f u ncti o n cal l o pe rato r. D o i ng so can l e ad to adde d f l e x i bi l i ty , adde d pe rf o rm ance , o r bo th .

22.4.1 A First Example of Class Type Functors

H e re i s a v e ry si m pl e e x am pl e o f a cl ass ty pe f u ncto r:

// functors/functor1.cpp #include <iostream> // class for function objects that return constant value class ConstantIntFunctor { private: int value; // value to return on ''function call'' public: // constructor: initialize value to return ConstantIntFunctor (int c) : value(c) { } // ''function call'' int operator() () const { return value; } }; // client function that uses the function object void client (ConstantIntFunctor const& cif) { std::cout << "calling back functor yields " << cif() << '\n'; } int main() { ConstantIntFunctor seven(7); ConstantIntFunctor fortytwo(42); client(seven); client(fortytwo); }

ConstantIntFunctor i s a cl ass ty pe f ro m w h i ch f u ncto rs can be g e ne rate d. T h at i s, i f y o u cre ate an o bj e ct w i th

ConstantIntFunctor seven(7); // create function object

Page 481: CPlusPlus Templates The Complete Guide

th e e x pre ssi o n

seven(); // call operator () for function object

i s a cal l o f operator () f o r th e o bj e ct seven rath e r th an a cal l o f f u ncti o n seven(). W e ach i e v e th e sam e e f f e ct (i ndi re ctl y ) w h e n passi ng th e f u ncti o n o bj e cts seven and fortytwo th ro u g h param e te r cif to client().

T h i s e x am pl e i l l u strate s w h at i s i n practi ce pe rh aps th e m o st i m po rtant adv antag e o f cl ass ty pe f u ncto rs o v e r po i nte rs to f u ncti o ns: th e abi l i ty to asso ci ate so m e state (data) w i th th e f u ncti o n. T h i s i s a f u ndam e ntal i m pro v e m e nt i n capabi l i ti e s f o r cal l back m e ch ani sm s. W e can h av e m u l ti pl e " i nstance s" o f a f u ncti o n w i th be h av i o r th at i s (i n a se nse ) param e te ri z e d.

22.4.2 Type of Class Type Functors

T h e re i s m o re to cl ass ty pe f u ncto rs th an th e addi ti o n o f state i nf o rm ati o n, h o w e v e r. In f act, i f a cl ass ty pe f u ncto r do e s no t e ncapsu l ate any state , i ts be h av i o r i s e nti re l y su bsu m e d by i ts ty pe , and i t i s su f f i ci e nt to pass th e ty pe as a te m pl ate arg u m e nt to cu sto m i z e a l i brary co m po ne nt' s be h av i o r.

A cl assi c i l l u strati o n o f th i s spe ci al case i ncl u de s co ntai ne r cl asse s th at m ai ntai n th e i r e l e m e nts i n so m e so rte d o rde r. T h e so rti ng cri te ri o n be co m e s a te m pl ate arg u m e nt, and be cau se i t i s part o f th e co ntai ne r' s ty pe , acci de ntal m i x i ng o f co ntai ne rs w i th di f f e re nt so rti ng cri te ri a (f o r e x am pl e , i n an assi g nm e nt) i s cau g h t by th e ty pe sy ste m .

T h e set and map co ntai ne rs o f th e C + + standard l i brary are param e te ri z e d th i s w ay . F o r e x am pl e , i f w e de f i ne tw o di f f e re nt se ts u si ng th e sam e e l e m e nt ty pe , Person, bu t di f f e re nt so rti ng cri te ri a, a co m pari so n o f th e se ts re su l ts i n a co m pi l e -ti m e e rro r:

#include <set> class Person { … }; class PersonSortCriterion { public: bool operator() (Person const& p1, Person const& p2) const { // returns whether p1 is ''less than'' p2 … } }; void foo()

Page 482: CPlusPlus Templates The Complete Guide

{ std::set<Person, std::less<Person> > c0, c1; // sort with operator < std::set<Person, std::greater<Person> > c2; // sort with operator > std::set<Person, PersonSortCriterion> c3; // sort with user- … // defined criterion c0 = c1; // OK: identical types c1 = c2; // ERROR: different types … if (c1 == c3) { // ERROR: different types … } }

F o r al l th re e de cl arati o ns o f a set, th e e l e m e nt ty pe and th e so rti ng cri te ri o n are passe d as te m pl ate arg u m e nts. T h e standard f u ncti o n o bj e ct ty pe te m pl ate std::less i s de f i ne d to re tu rn th e re su l t o f o pe rato r < as a re su l t o f a " f u ncti o n cal l ." T h e f o l l o w i ng si m pl i f i e d i m pl e m e ntati o n o f std::less cl ari f i e s th e i de a [5 ]:

[5 ] T h e e x act i m pl e m e ntati o n di f f e rs be cau se i t i s de ri v e d f ro m a cl ass std::binary_function. S e e S e cti o n 8 .2 .4 o f [J o su tti sS tdL i b] f o r de tai l s.

namespace std { template <typename T> class less { public: bool operator() (T const& x, T const& y) const { returnx<y; } }; }

T h e std::greater te m pl ate i s si m i l ar.

B e cau se al l th re e so rti ng cri te ri a h av e di f f e re nt ty pe s, th e re su l ti ng se ts al so h av e di f f e re nt ty pe s. T h e re f o re , any atte m pt to assi g n o r to co m pare tw o o f th e se se ts f ai l s at co m pi l e ti m e (th e co m pari so n o pe rato r re q u i re s th e sam e ty pe ). T h i s m ay se e m strai g h tf o rw ard, bu t pri o r to te m pl ate s, th e so rti ng cri te ri o n m i g h t h av e be e n m ai ntai ne d as a f u ncti o n po i nte r f i e l d o f th e co ntai ne r. A ny m i sm atch w o u l d l i k e l y no t h av e be e n de te cte d u nti l ru n ti m e (and pe rh aps no t w i th o u t m u ch f ru strati ng de te cti v e w o rk ).

Page 483: CPlusPlus Templates The Complete Guide

22.5 Specifying Functors

O u r pre v i o u s e x am pl e o f th e standard set cl ass sh o w s o nl y o ne w ay to h andl e th e se l e cti o n o f f u ncto rs. A nu m be r o f di f f e re nt appro ach e s are di scu sse d i n th i s se cti o n.

22.5.1 Functors as Template Type Arguments

O ne w ay to pass a f u ncto r i s to m ak e i ts ty pe a te m pl ate arg u m e nt. A ty pe by i tse l f i s no t a f u ncto r, h o w e v e r, so th e cl i e nt f u ncti o n o r cl ass m u st cre ate a f u ncto r o bj e ct w i th th e g i v e n ty pe . T h i s, o f co u rse , i s po ssi bl e o nl y f o r cl ass ty pe f u ncto rs, and i t ru l e s o u t f u ncti o n po i nte r ty pe s. A f u ncti o n po i nte r ty pe do e s no t by i tse l f spe ci f y any be h av i o r. A l o ng th e sam e l i ne s o f th o u g h t, th i s i s no t an appro pri ate m e ch ani sm to pass a cl ass ty pe f u ncto r th at e ncapsu l ate s so m e state i nf o rm ati o n (be cau se no parti cu l ar state i s e ncapsu l ate d by th e ty pe al o ne ; a spe ci f i c o bj e ct o f th at ty pe i s ne e de d).

H e re i s an o u tl i ne o f a f u ncti o n te m pl ate th at tak e s a f u ncto r cl ass ty pe as a so rti ng cri te ri o n:

template <typename FO> void my_sort (… ) { FO cmp; // create function object … if (cmp(x,y)) { // use function object to compare two values … } … } // call function with functor my_sort<std::less<… > > (… );

W i th th i s appro ach , th e se l e cti o n o f th e co m pari so n co de h as be co m e a co m pi l e -ti m e af f ai r. A nd be cau se th e co m pari so n can be " i nl i ne d, " a g o o d o pti m i z i ng co m pi l e r sh o u l d be abl e to pro du ce co de th at i s e sse nti al l y e q u i v al e nt to re pl aci ng th e f u ncto r cal l s by di re ct appl i cati o ns o f th e re su l ti ng o pe rati o ns. T o be e nti re l y pe rf e ct, an o pti m i z e r m u st al so be abl e to e l i de th e sto rag e u se d by th e cmp f u ncto r o bj e ct. In practi ce , h o w e v e r, o nl y a f e w co m pi l e rs are capabl e o f su ch f e atu re s.

22.5.2 Functors as Function Call Arguments

A no th e r w ay to pass f u ncto rs i s to pass th e m as f u ncti o n cal l arg u m e nts. T h i s

Page 484: CPlusPlus Templates The Complete Guide

al l o w s th e cal l e r to co nstru ct th e f u ncti o n o bj e ct (po ssi bl y u si ng a no ntri v i al co nstru cto r) at ru n ti m e .

T h e e f f i ci e ncy arg u m e nt i s e sse nti al l y si m i l ar to th at o f h av i ng j u st a f u ncto r ty pe param e te r, e x ce pt th at w e m u st no w co py a f u ncto r o bj e ct as i t i s passe d i nto th e ro u ti ne . T h i s co st i s u su al l y l o w and can i n f act be re du ce d to z e ro i f th e f u ncto r o bj e ct h as no data m e m b e rs (w h i ch i s o f te n th e case ). Inde e d, co nsi de r th i s v ari ati o n o f o u r my_sort e x am pl e :

template <typename F> void my_sort (… , F cmp) { … if (cmp(x,y)) { // use function object to compare two values … } … } // call function with functor my_sort (… , std::less<… >());

W i th i n th e my_sort() f u ncti o n, w e are de al i ng w i th a co py cmp o f th e v al u e passe d i n. W h e n th i s v al u e i s an e m pty cl ass o bj e ct, th e re i s no state to di sti ng u i sh a l o cal l y co nstru cte d f u ncto r o bj e ct f ro m a co py passe d i n. T h e re f o re , i nste ad o f actu al l y passi ng th e " e m pty f u ncto r" as a f u ncti o n cal l arg u m e nt, th e co m pi l e r co u l d j u st u se i t f o r o v e rl o ad re so l u ti o n and th e n e l i de th e param e te r/arg u m e nt al to g e th e r. Insi de th e i nstanti ate d f u ncti o n, a du m m y l o cal o bj e ct can th e n se rv e as th e f u ncto r.

T h i s al m o st w o rk s, e x ce pt th at th e co py co nstru cto r o f th e " e m pty f u ncto r" m u st al so be f re e o f si de e f f e cts. In practi ce th i s m e ans th at any f u ncto r w i th a u se r-de f i ne d co py co nstru cto r sh o u l d no t be o pti m i z e d th i s w ay .

A s w ri tte n, th e adv antag e o f th i s f u ncto r spe ci f i cati o n te ch ni q u e i s th at i t i s al so po ssi bl e to pass an o rdi nary f u ncti o n po i nte r as arg u m e nt. F o r e x am pl e :

bool my_criterion () (T const& x, T const& y); // call function with function object my_sort (… , my_criterion);

M any pro g ram m e rs al so pre f e r th e f u ncti o n cal l sy ntax o v e r th e sy ntax i nv o l v i ng a te m pl ate ty pe arg u m e nt.

22.5.3 Combining Function Call Parameters and Template Type Parameters

It i s po ssi bl e to co m bi ne th e tw o pre v i o u s f o rm s o f passi ng f u ncto rs to f u ncti o ns

Page 485: CPlusPlus Templates The Complete Guide

and cl asse s by de f i ni ng de f au l t f u ncti o n cal l arg u m e nts:

template <typename F> void my_sort (… , F cmp = F()) { … if (cmp(x,y)) { // use function object to compare two values … } … } bool my_criterion () (T const& x, T const& y); // call function with functor passed as template argument my_sort<std::less<… > > (… ); // call function with functor passed as value argument my_sort (… , std::less<… >()); // call function with function pointer passed as value argument my_sort (… , my_criterion);

T h e o rde re d co l l e cti o n cl asse s o f th e C + + standard l i brary are de f i ne d i n th i s w ay : T h e so rti ng cri te ri o n can be passe d as a co nstru cto r arg u m e nt at ru n ti m e :

class RuntimeCmp { … }; // pass sorting criterion as a compile-time template argument // (uses default constructor of sorting criterion) set<int,RuntimeCmp> c1; // pass sorting criterion as a run-time constructor argument set<int,RuntimeCmp> c2(RuntimeCmp(… ));

F o r de tai l s, se e pag e s 1 7 8 and 1 9 7 o f [J o su tti sS tdL i b].

22.5.4 Functors as Nontype Template Arguments

F u ncto rs can al so be pro v i de d th ro u g h no nty pe te m pl ate arg u m e nts. H o w e v e r, as m e nti o ne d i n S e cti o n 4 .3 o n pag e 4 0 and S e cti o n 8 .3 .3 o n pag e 1 0 9 , a cl ass ty pe f u ncto r (and, i n g e ne ral , a cl ass ty pe o bj e ct) i s ne v e r a v al i d no nty pe te m pl ate arg u m e nt. F o r e x am pl e , th e f o l l o w i ng i s i nv al i d:

class MyCriterion { public: bool operator() (SomeType const&, SomeType const&) const; }; template <MyCriterion F> // ERROR: MyCriterion is a class type void my_sort (… );

Page 486: CPlusPlus Templates The Complete Guide

H o w e v e r, i t i s po ssi bl e to h av e a po i nte r o r re f e re nce to a cl ass ty pe o bj e ct as a no nty pe arg u m e nt. T h i s m i g h t i nspi re u s to w ri te th e f o l l o w i ng :

class MyCriterion { public: virtual bool operator() (SomeType const&, SomeType const&) const = 0; }; class LessThan : public MyCriterion { public: virtual bool operator() (SomeType const&, SomeType const&) const; }; template<MyCriterion& F> void sort (… ); LessThan order; sort<order> (… ); // ERROR: requires derived-to-base // conversion sort<(MyCriterion&)order> (… ); // ERROR: reference nontype argument // must be simple name // (without a cast)

O u r i de a i n th e pre v i o u s e x am pl e i s to captu re th e i nte rf ace o f th e so rti ng cri te ri o n i n an abstract base cl ass ty pe and u se th at ty pe f o r th e no nty pe te m pl ate param e te r. In an i de al w o rl d, w e co u l d th e n j u st pl u g i n de ri v e d cl asse s (su ch as LessThan) to re q u e st a spe ci f i c i m pl e m e ntati o n o f th e base cl ass i nte rf ace (MyCriterion). U nf o rtu nate l y , C + + do e s no t pe rm i t su ch an appro ach : No nty pe arg u m e nts w i th re f e re nce o r po i nte r ty pe s m u st m atch th e param e te r ty pe e x actl y . A n i m pl i ci t de ri v e d-to -base co nv e rsi o n i s no t co nsi de re d, and m ak i ng th e co nv e rsi o n e x pl i ci t al so i nv al i date s th e arg u m e nt.

In l i g h t o f o u r pre v i o u s e x am pl e s, w e co ncl u de th at cl ass ty pe f u ncto rs are no t co nv e ni e ntl y passe d as no nty pe te m pl ate arg u m e nts. In co ntrast, po i nte rs (and re f e re nce s) to f u ncti o ns can be v al i d no nty pe te m pl ate arg u m e nts. T h e f o l l o w i ng se cti o n e x pl o re s so m e o f th e po ssi bi l i ti e s o f f e re d by th i s co nce pt.

22.5.5 Function Pointer Encapsulation

S u ppo se w e h av e a f ram e w o rk th at e x pe cts f u ncto rs l i k e th e so rti ng cri te ri a o f th e e x am pl e s i n th e pre v i o u s se cti o ns. F u rth e rm o re , w e m ay h av e so m e f u ncti o ns f ro m an o l de r (no nte m pl ate ) l i brary th at w e ' d l i k e to act as su ch a f u ncto r.

T o so l v e th i s pro bl e m , w e can si m pl y w rap th e f u ncti o n cal l . F o r e x am pl e :

class CriterionWrapper {

Page 487: CPlusPlus Templates The Complete Guide

public: bool operator() (… ) { return wrapped_function(… ); } };

H e re , w r a p p e d_ f unc t i on() i s a l e g acy f u ncti o n th at w e l i k e to f i t i n o u r m o re g e ne ral f u ncto r f ram e w o rk .

O f te n, th e ne e d to i nte g rate l e g acy f u ncti o ns i n a f ram e w o rk o f cl ass ty pe f u ncto rs i s no t an i so l ate d e v e nt. T h e re f o re , i t can be co nv e ni e nt to de f i ne a te m pl ate th at co nci se l y i nte g rate s su ch f u ncti o ns:

template<int (*FP)()> class FunctionReturningIntWrapper { public: int operator() () { return FP(); } };

H e re i s a co m pl e te e x am pl e :

// functors/funcwrap.cpp #include <vector> #include <iostream> #include <cstdlib> // wrapper for function pointers to function objects template<int (*FP)()> class FunctionReturningIntWrapper { public: int operator() () { return FP(); } }; // example function to wrap int random_int() { return std::rand(); // call standard C function } // client that uses function object type as template parameter template <typename FO> void initialize (std::vector<int>& coll) { FO fo; // create function object for (std::vector<int>::size_type i=0; i<coll.size(); ++i) { coll[i] = fo(); // call function for function object } } int main() {

Page 488: CPlusPlus Templates The Complete Guide

// create vector with 10 elements std::vector<int> v(10); // (re)initialize values with wrapped function initialize<FunctionReturningIntWrapper<random_int> >(v); // output elements for (std::vector<int>::size_type i=0; i<v.size(); ++i) { std::cout << "coll[" << i << "]: " << v[i] << std::endl; } }

T h e e x pre ssi o n

FunctionReturningIntWrapper<random_int>

i nsi de th e cal l o f initialize() w raps th e f u ncti o n po i nte r random_int so th at i t can be passe d as a te m pl ate ty pe param e te r.

No te th at w e can' t pass a f u ncti o n po i nte r w i th C l i nk ag e to th i s te m pl ate . F o r e x am pl e ,

initialize<FunctionReturningIntWrapper<std::rand> >(v);

m ay no t w o rk be cau se th e std::rand() f u ncti o n co m e s f ro m th e C standard l i brary (and m ay th e re f o re h av e C l i nk ag e [6 ]). Inste ad, w e can i ntro du ce a ty pe de f f o r a f u ncti o n po i nte r ty pe w i th th e appro pri ate l i nk ag e :

[6 ] In m any i m pl e m e ntati o ns, f u ncti o ns f ro m th e C standard l i brary h av e C l i nk ag e , bu t a C + + i m pl e m e ntati o n i s al l o w e d to pro v i de th e se f u ncti o ns w i th C + + l i nk ag e i nste ad. W h e th e r th e e x am pl e cal l i s v al i d th e re f o re de pe nds o n th e parti cu l ar i m pl e m e ntati o n be i ng u se d.

// type for function pointer with C linkage extern "C" typedef int (*C_int_FP)(); // wrapper for function pointers to function objects template<C_int_FP FP> class FunctionReturningIntWrapper { public: int operator() () { return FP(); } };

It m ay be w o rth w h i l e to re e m ph asi z e at th i s po i nt th at te m pl ate s co rre spo nd to a co m pi l e -ti m e m e ch ani sm . T h i s m e ans th at th e co m pi l e r k no w s w h i ch v al u e i s su bsti tu te d f o r th e no nty pe param e te r FP o f th e te m pl ate FunctionReturningIntWrapper. B e cau se o f th i s, m o st C + + i m pl e m e ntati o ns

Page 489: CPlusPlus Templates The Complete Guide

sh o u l d be abl e to co nv e rt w h at at f i rst m ay l o o k l i k e an i ndi re ct cal l to a di re ct cal l . Inde e d, i f th e f u ncti o n w e re i nl i ne and i ts de f i ni ti o n v i si bl e at th e po i nt o f th e f u ncto r i nv o cati o n, i t w o u l d be re aso nabl e to e x pe ct th e cal l to be i nl i ne .

Page 490: CPlusPlus Templates The Complete Guide

22.6 Introspection

In th e co nte x t o f pro g ram m i ng , th e te rm i nt r os p e c t i on re f e rs to th e abi l i ty o f a pro g ram to i nspe ct i tse l f . F o r e x am pl e , i n C h apte r 1 5 w e de si g ne d te m pl ate s th at can i nspe ct a ty pe and de te rm i ne w h at k i nd o f ty pe i t i s. F o r f u ncto rs, i t i s o f te n u se f u l to be abl e to te l l , f o r e x am pl e , h o w m any arg u m e nts th e f u ncto r acce pts, th e re tu rn ty pe o f th e f u ncto r, o r th e nth param e te r ty pe o f th e f u ncto r ty pe .

Intro spe cti o n i s no t e asi l y ach i e v e d f o r an arbi trary f u ncto r. F o r e x am pl e , h o w w o u l d w e w ri te a ty pe f u ncti o n th at e v al u ate s to th e ty pe o f th e se co nd param e te r i n a f u ncto r l i k e th e f o l l o w i ng ?

class SuperFunc { public: void operator() (int, char**); };

S o m e C + + co m pi l e rs pro v i de a spe ci al ty pe f u ncti o n k no w n as typeof. It e v al u ate s to th e ty pe o f i ts arg u m e nt e x pre ssi o n (bu t do e sn' t actu al l y e v al u ate th e e x pre ssi o n, m u ch l i k e th e sizeof o pe rato r). W i th su ch an o pe rato r, th e pre v i o u s pro bl e m can be so l v e d to a l arg e e x te nt, al be i t no t e asi l y . T h e typeof co nce pt i s di scu sse d i n S e cti o n 1 3 .8 o n pag e 2 1 5 .

A l te rnati v e l y , w e can de v e l o p a f u ncto r f ram e w o rk th at re q u i re s parti ci pati ng f u ncto rs to pro v i de so m e e x tra i nf o rm ati o n to e nabl e so m e l e v e l o f i ntro spe cti o n. T h i s i s th e appro ach w e u se i n th e re m ai nde r o f th i s ch apte r.

22.6.1 Analyzing a Functor Type

In o u r f ram e w o rk , w e h andl e o nl y cl ass ty pe f u ncto rs [7 ] and re q u i re th e m to pro v i de th e f o l l o w i ng i nf o rm ati o n:

[7 ] T o re du ce th e stre ng th o f th i s co nstrai nt, w e al so de v e l o p a to o l to e ncapsu l ate f u ncti o n po i nte rs i n th e f ram e w o rk .

• T h e nu m be r o f param e te rs o f th e f u ncto r (as a m e m be r e nu m e rato r co nstant NumParams)

• T h e ty pe o f e ach param e te r (th ro u g h m e m be r ty pe de f s Param1T , Param2T, Param3T, ...)

• T h e re tu rn ty pe o f th e f u ncto r (th ro u g h a m e m be r ty pe de f ReturnT)

F o r e x am pl e , w e co u l d re w ri te o u r PersonSortCriterion as f o l l o w s to f i t th i s

Page 491: CPlusPlus Templates The Complete Guide

f ram e w o rk :

class PersonSortCriterion { public: enum { NumParams = 2 }; typedef bool ReturnT; typedef Person const& Param1T; typedef Person const& Param2T; bool operator() (Person const& p1, Person const& p2) const { // returns whether p1 is ''less than'' p2 … } };

T h e se co nv e nti o ns are su f f i ci e nt f o r o u r pu rpo se s. T h e y al l o w u s to w ri te te m pl ate s to cre ate ne w f u ncto rs f ro m e x i sti ng o ne s (f o r e x am pl e , th ro u g h co m po si ti o n).

T h e re are o th e r pro pe rti e s o f a f u ncto r th at can be w o rth re pre se nti ng i n th i s m anne r. F o r e x am pl e , w e co u l d de ci de to e nco de th e f act th at a f u ncto r h as no si de e f f e cts and u se th i s i nf o rm ati o n to o pti m i z e ce rtai n g e ne ri c te m pl ate s. S u ch f u ncto rs are so m e ti m e s cal l e d p ur e f unc t or s . It w o u l d al so be u se f u l to e nabl e i ntro spe cti o n o f th i s pro pe rty to e nf o rce th e ne e d f o r a pu re f u ncto r at co m pi l e ti m e . F o r e x am pl e , u su al l y a so rti ng cri te ri o n sh o u l d be pu re [8 ] ; o th e rw i se , th e re su l ts o f th e so rti ng o pe rati o n co u l d be m e ani ng l e ss.

[8 ] A t l e ast to a l arg e e x te nt. S o m e cach i ng and l o g g i ng si de e f f e cts can be to l e rate d to th e e x te nt th at th e y do n' t af f e ct th e v al u e re tu rne d by th e f u ncto r.

22.6.2 Accessing Parameter Types

A f u ncto r can h av e an arbi trary nu m be r o f param e te rs. W i th o u r co nv e nti o ns i t i s re l ati v e l y strai g h tf o rw ard to acce ss, say , th e e i g h th param e te r ty pe : Param8T. H o w e v e r, w h e n de al i ng w i th te m pl ate s i t i s al w ay s u se f u l to pl an f o r m ax i m u m f l e x i bi l i ty . In th i s case , h o w do w e w ri te a ty pe f u ncti o n th at pro du ce s th e Nth param e te r ty pe g i v e n th e f u ncto r ty pe and a co nstant N ? W e can do th i s by w ri ti ng parti al spe ci al i z ati o ns o f th e f o l l o w i ng cl ass te m pl ate :

template<typename FunctorType, int N> class FunctorParam;

W e can pro v i de parti al spe ci al i z ati o ns f o r v al u e s o f N f ro m o ne to so m e re aso nabl y l arg e nu m be r (say 2 0 ; f u ncto rs rare l y h av e m o re th an 2 0 param e te rs). E ach o f th e se parti al spe ci al i z ati o ns can th e n de f i ne a m e m be r ty pe de f Type th at re f l e cts th e co rre spo ndi ng param e te r ty pe .

Page 492: CPlusPlus Templates The Complete Guide

T h i s pre se nts o ne di f f i cu l ty : T o w h at sh o u l d FunctorParam<F, N>::Type e v al u ate w h e n N i s l arg e r th an th e nu m be r o f param e te rs o f th e f u ncto r F? O ne po ssi bi l i ty i s to l e t su ch si tu ati o ns re su l t i n a co m pi l ati o n e rro r. A l th o u g h th i s i s e asi l y acco m pl i sh e d, i t m ak e s th e FunctorParam ty pe f u ncti o n m u ch l e ss u se f u l th an i t co u l d be . A se co nd po ssi bi l i ty i s to de f au l t to ty pe void. T h e di sadv antag e o f th i s appro ach i s th at th e re are so m e u nf o rtu nate re stri cti o ns o n ty pe void ; f o r e x am pl e , a f u ncti o n canno t h av e a param e te r ty pe o f ty pe void , no r can w e cre ate re f e re nce s to void. T h e re f o re , w e o pt f o r a th i rd po ssi bi l i ty : a pri v ate m e m be r cl ass ty pe . O bj e cts o f su ch a ty pe are no t e asi l y co nstru cte d, bu t th e re are f e w sy ntacti c co nstrai nts o n th e i r u se . H e re i s an i m pl e m e ntati o n o f th i s i de a:

// functors/functorparam1.hpp #include "ifthenelse.hpp" template <typename F, int N> class UsedFunctorParam; template <typename F, int N> class FunctorParam { private: class Unused { private: class Private {}; public: typedef Private Type; }; public: typedef typename IfThenElse<F::NumParams>=N, UsedFunctorParam<F,N>, Unused>::ResultT::Type Type; }; template <typename F> class UsedFunctorParam<F, 1> { public: typedef typename F::Param1T Type; };

T h e IfThenElse te m pl ate w as i ntro du ce d i n S e cti o n 1 5 .2 .4 o n pag e 2 7 2 . No te th at w e i ntro du ce d a h e l pe r te m pl ate UsedFunctorParam, and i t i s th i s te m pl ate th at ne e ds to be parti al l y spe ci al i z e d f o r spe ci f i c v al u e s o f N. A co nci se w ay to do th i s i s to u se a m acro :

// functors/functorparam2.hpp #define FunctorParamSpec(N) \ template<typename F> \ class UsedFunctorParam<F, N> { \ public: \ typedef typename F::Param##N##T Type; \

Page 493: CPlusPlus Templates The Complete Guide

} … FunctorParamSpec(2); FunctorParamSpec(3); … FunctorParamSpec(20); #undef FunctorParamSpec

22.6.3 Encapsulating Function Pointers

R e q u i ri ng th at f u ncto r ty pe s su ppo rt so m e i ntro spe cti o n i n th e f o rm o f m e m b e r ty pe de f s e x cl u de s th e u se o f f u ncti o n po i nte rs i n o u r f ram e w o rk . A s di scu sse d e arl i e r, w e can m i ti g ate th i s l i m i tati o n by e ncapsu l ati ng th e f u ncti o n po i nte r. L e t' s de v e l o p a sm al l to o l th at e nabl e s u s to e ncapsu l ate f u ncti o ns w i th as m any as tw o param e te rs (a l arg e r nu m be r o f param e te rs are h andl e d i n th e sam e w ay , bu t l e t' s k e e p th e nu m be r sm al l i n th e i nte re st o f cl ari ty ). W e co v e r o nl y th e case o f f u ncti o ns w i th C + + l i nk ag e ; C l i nk ag e can be do ne i n a si m i l ar w ay .

T h e so l u ti o n pre se nte d h e re h as tw o m ai n co m po ne nts: a cl ass te m pl ate FunctionPtr w i th i nstance s th at are f u ncto r ty pe s e ncapsu l ati ng a f u ncti o n po i nte r, and an o v e rl o ade d f u ncti o n te m pl ate func_ptr() th at tak e s a f u ncti o n po i nte r and re tu rns a co rre spo ndi ng f u ncto r th at f i ts o u r f ram e w o rk . T h e cl ass te m pl ate i s param e te ri z e d w i th th e re tu rn ty pe and th e param e te r ty pe s:

template<typename RT, typename P1 = void, typename P2 = void> class FunctionPtr;

S u bsti tu ti ng a param e te r w i th ty pe void am o u nts to say i ng th at th e param e te r i sn' t actu al l y av ai l abl e . H e nce , o u r te m pl ate i s abl e to h andl e m u l ti pl e nu m be rs o f f u ncto r cal l arg u m e nts.

B e cau se w e ne e d to e ncapsu l ate a f u ncti o n po i nte r, w e ne e d a to o l to cre ate th e ty pe o f th e f u ncti o n po i nte r f ro m th e param e te r ty pe s. T h i s i s ach i e v e d th ro u g h parti al spe ci al i z ati o n as f o l l o w s:

// functors/functionptrt.hpp // primary template handles maximum number of parameters: template<typename RT, typename P1 = void, typename P2 = void, typename P3 = void> class FunctionPtrT { public: enum { NumParams = 3 }; typedef RT (*Type)(P1,P2,P3); }; // partial specialization for two parameters: template<typename RT, typename P1,

Page 494: CPlusPlus Templates The Complete Guide

typename P2> class FunctionPtrT<RT, P1, P2, void> { public: enum { NumParams = 2 }; typedef RT (*Type)(P1,P2); }; // partial specialization for one parameter: template<typename RT, typename P1> class FunctionPtrT<RT, P1, void, void> { public: enum { NumParams = 1 }; typedef RT (*Type)(P1); }; // partial specialization for no parameters: template<typename RT> class FunctionPtrT<RT, void, void, void> { public: enum { NumParams = 0 }; typedef RT (*Type)(); };

No ti ce h o w w e u se d th e sam e te m pl ate to " co u nt" th e nu m be r o f param e te rs.

T h e f u ncto r ty pe w e are de v e l o pi ng passe s i ts param e te rs to th e f u ncti o n po i nte r i t e ncapsu l ate s. P assi ng a f u ncti o n cal l arg u m e nt can h av e si de e f f e cts: If th e co rre spo ndi ng param e te r h as a cl ass ty pe (and no t a r e f e r e nc e to a cl ass ty pe ), i ts co py co nstru cto r i s i nv o k e d. T o av o i d th i s e x tra co st, i t i s u se f u l to h av e a ty pe f u ncti o n th at l e av e s i ts arg u m e nt ty pe u nch ang e d, e x ce pt i f i t i s a cl ass ty pe , i n w h i ch case a re f e re nce to th e co rre spo ndi ng const cl ass ty pe i s pro du ce d. W i th th e TypeT te m pl ate de v e l o pe d i n C h apte r 1 5 and o u r IfThenElse u ti l i ty te m pl ate , th i s i s ach i e v e d f ai rl y co nci se l y :

// functors/forwardparam.hpp #ifndef FORWARD_HPP #define FORWARD_HPP #include "ifthenelse.hpp" #include "typet.hpp" #include "typeop.hpp" // ForwardParamT<T>::Type is // - constant reference for class types // - plain type for almost all other types // - a dummy type (Unused) for type void template<typename T> class ForwardParamT { public: typedef typename IfThenElse<TypeT<T>::IsClassT, typename TypeOp<T>::RefConstT, typename TypeOp<T>::ArgT >::ResultT Type;

Page 495: CPlusPlus Templates The Complete Guide

}; template<> class ForwardParamT<void> { private: class Unused {}; public: typedef Unused Type; }; #endif // FORWARD_HPP

No te th e si m i l ari ty o f th i s te m pl ate w i th th e RParam te m pl ate de v e l o pe d i n S e cti o n 1 5 .3 .1 o n pag e 2 7 6 . T h e di f f e re nce i s th at w e ne e d to m ap th e ty pe void (w h i ch , as m e nti o ne d e arl i e r, i s u se d to de no te an u nu se d param e te r ty pe ) to a ty pe th at can v al i dl y appe ar as a param e te r ty pe .

W e are no w re ady to de f i ne th e FunctionPtr te m pl ate . B e cau se w e do n' t k no w a p r i or i h o w m any param e te rs i t w i l l tak e , w e o v e rl o ad th e f u ncti o n cal l o pe rato r f o r e v e ry nu m be r o f param e te rs (u p to th re e i n o u r case ):

// functors/functionptr.hpp #include "forwardparam.hpp" #include "functionptrt.hpp" template<typename RT, typename P1 = void, typename P2 = void, typename P3 = void> class FunctionPtr { private: typedef typename FunctionPtrT<RT,P1,P2,P3>::Type FuncPtr; // the encapsulated pointer: FuncPtr fptr; public: // to fit in our framework: enum { NumParams = FunctionPtrT<RT,P1,P2,P3>::NumParams }; typedef RT ReturnT; typedef P1 Param1T; typedef P2 Param2T; typedef P3 Param3T; // constructor: FunctionPtr(FuncPtr ptr) : fptr(ptr) { } // ''function calls'': RT operator()() { return fptr(); } RT operator()(typename ForwardParamT<P1>::Type a1) { return fptr(a1); } RT operator()(typename ForwardParamT<P1>::Type a1, typename ForwardParamT<P2>::Type a2) {

Page 496: CPlusPlus Templates The Complete Guide

return fptr(a1, a2); } RT operator()(typename ForwardParamT<P1>::Type a1, typename ForwardParamT<P2>::Type a2, typename ForwardParamT<P2>::Type a3) { return fptr(a1, a2, a3); } };

T h i s cl ass te m pl ate w o rk s w e l l , bu t u si ng i t di re ctl y can be cu m be rso m e . A f e w (i nl i ne ) f u ncti o n te m pl ate s al l o w u s to e x pl o i t th e te m pl ate arg u m e nt de du cti o n m e ch ani sm to al l e v i ate th i s bu rde n:

// functors/funcptr.hpp #include "functionptr.hpp" template<typename RT> inline FunctionPtr<RT> func_ptr (RT (*fp)()) { return FunctionPtr<RT>(fp); } template<typename RT, typename P1> inline FunctionPtr<RT,P1> func_ptr (RT (*fp)(P1)) { return FunctionPtr<RT,P1>(fp); } template<typename RT, typename P1, typename P2> inline FunctionPtr<RT,P1,P2> func_ptr (RT (*fp)(P1,P2)) { return FunctionPtr<RT,P1,P2>(fp); } template<typename RT, typename P1, typename P2, typename P3> inline FunctionPtr<RT,P1,P2,P3> func_ptr (RT (*fp)(P1,P2,P3)) { return FunctionPtr<RT,P1,P2,P3>(fp); }

A l l th e re i s l e f t to do i s to try th e adv ance d te m pl ate to o l w e j u st de v e l o pe d w i th th e f o l l o w i ng l i ttl e de m o nstrati o n pro g ram :

// functors/functordemo.cpp #include <iostream> #include <string> #include <typeinfo> #include "funcptr.hpp" double seven() { return 7.0; }

Page 497: CPlusPlus Templates The Complete Guide

std::string more() { return std::string("more"); } template <typename FunctorT> void demo (FunctorT func) { std::cout << "Functor returns type " << typeid(typename FunctorT::ReturnT).name() << '\n' << "Functor returns value " << func() << '\n'; } int main() { demo(func_ptr(seven)); demo(func_ptr(more)); }

Page 498: CPlusPlus Templates The Complete Guide

22.7 Function Object Composition

L e t' s assu m e w e h av e th e f o l l o w i ng tw o si m pl e m ath e m ati cal f u ncto rs i n o u r f ram e w o rk :

// functors/math1.hpp #include <cmath> #include <cstdlib> class Abs { public: // ''function call'': double operator() (double v) const { return std::abs(v); } }; class Sine { public: // ''function call'': double operator() (double a) const { return std::sin(a); } };

H o w e v e r, th e f u ncto r w e re al l y w ant i s th e o ne th at co m pu te s th e abso l u te v al u e o f th e si ne o f a g i v e n ang l e . W ri ti ng th e ne w f u ncto r i s no t h ard:

class AbsSine { public: double operator() (double a) { return std::abs(std::sin(a)); } };

Ne v e rth e l e ss, i t i s i nco nv e ni e nt to w ri te ne w de cl arati o ns f o r e v e ry ne w co m bi nati o n o f f u ncto rs. Inste ad, w e m ay pre f e r to w ri te a f u ncto r u ti l i ty th at c om p os e s tw o o th e r f u ncto rs. In th i s se cti o n w e de v e l o p so m e te m pl ate s th at e nabl e u s to do th i s. A l o ng th e w ay , w e i ntro du ce v ari o u s co nce pts th at pro v e u se f u l i n th e re m ai nde r o f th i s ch apte r.

22.7.1 Simple Composition

L e t' s start w i th a f i rst cu t at an i m pl e m e ntati o n o f a co m po si ti o n to o l :

// functors/compose1.hpp

Page 499: CPlusPlus Templates The Complete Guide

template <typename FO1, typename FO2> class Composer { private: FO1 fo1; // first/inner function object to call FO2 fo2; // second/outer function object to call public: // constructor: initialize function objects Composer (FO1 f1, FO2 f2) : fo1(f1), fo2(f2) { } // ''function call'': nested call of function objects double operator() (double v) { return fo2(fo1(v)); } };

No te th at w h e n de scri bi ng th e co m po si ti o n o f tw o f u ncti o ns, th e f u ncti o n th at i s a p p l i e d f i rst i s l i ste d f i rst. T h i s m e ans th at th e no tati o n Composer<Abs, Sine> co rre spo nds to th e f u ncti o n sin (abs (x )) (no te th e re v e rsal o f o rde r). T o te st o u r l i ttl e te m pl ate , w e can u se th e f o l l o w i ng pro g ram :

// functors/compose1.cpp #include <iostream> #include "math1.hpp" #include "compose1.hpp" template<typename FO> void print_values (FO fo) { for (int i=-2; i<3; ++i) { std::cout << "f(" << i*0.1 << ") = " << fo(i*0.1) << "\n"; } } int main() { // print sin(abs(-0.5)) std::cout << Composer<Abs,Sine>(Abs(),Sine())(0.5) << "\n\n"; // print abs() of some values print_values(Abs()); std::cout << '\n'; // print sin() of some values print_values(Sine()); std::cout << '\n'; // print sin(abs()) of some values print_values(Composer<Abs, Sine>(Abs(), Sine())); std::cout << '\n'; // print abs(sin()) of some values print_values(Composer<Sine, Abs>(Sine(), Abs())); }

Page 500: CPlusPlus Templates The Complete Guide

T h i s de m o nstrate s th e g e ne ral pri nci pl e , bu t th e re i s ro o m f o r v ari o u s i m pro v e m e nts.

A u sabi l i ty i m pro v e m e nt i s ach i e v e d by i ntro du ci ng a sm al l i nl i ne h e l pe r f u ncti o n so th at th e te m pl ate arg u m e nts f o r Composer m ay be de du ce d (by no w , th i s i s a rath e r co m m o n te ch ni q u e ):

// functors/composeconv.hpp template <typename FO1, typename FO2> inline Composer<FO1,FO2> compose (FO1 f1, FO2 f2) { return Composer<FO1,FO2> (f1, f2); }

W i th th i s i n pl ace , o u r sam pl e pro g ram can no w be re w ri tte n as f o l l o w s:

// functors/compose2.cpp #include <iostream> #include "math1.hpp" #include "compose1.hpp" #include "composeconv.hpp" template<typename FO> void print_values (FO fo) { for (int i=-2; i<3; ++i) { std::cout << "f(" << i*0.1 << ") = " << fo(i*0.1) << "\n"; } } int main() { // print sin(abs(-0.5)) std::cout << compose(Abs(),Sine())(0.5) << "\n\n"; // print abs() of some values print_values(Abs()); std::cout << '\n'; // print sin() of some values print_values(Sine()); std::cout << '\n'; // print sin(abs()) of some values print_values(compose(Abs(),Sine())); std::cout << '\n'; // print abs(sin()) of some values print_values(compose(Sine(),Abs())); }

Page 501: CPlusPlus Templates The Complete Guide

Inste ad o f

Composer<Abs, Sine>(Abs(), Sine())

w e can no w u se th e m o re co nci se

compose(Abs(), Sine())

T h e ne x t re f i ne m e nt i s dri v e n by a de si re to o pti m i z e th e Composer cl ass te m pl ate i tse l f . M o re spe ci f i cal l y , w e w ant to av o i d h av i ng to al l o cate any space f o r th e m e m b e rs f u ncto rs first and second i f th e se f u ncto rs are th e m se l v e s e m pty cl asse s (th at i s, w h e n th e y are s t a t e l e s s ), w h i ch i s a co m m o n spe ci al case . T h i s m ay se e m to be a m o de st sav i ng s i n sto rag e , bu t re m e m be r th at e m pty cl asse s can u nde rg o a spe ci al o pti m i z ati o n w h e n passe d as f u ncti o n cal l param e te rs. T h e standard te ch ni q u e f o r o u r pu rpo se i s th e e m p t y b a s e c l a s s op t i m i z a t i on (se e S e cti o n 1 6 .2 o n pag e 2 8 9 ), w h i ch tu rns th e m e m b e rs i nto base cl asse s:

// functors/compose3.hpp template <typename FO1, typename FO2> class Composer : private FO1, private FO2 { public: // constructor: initialize function objects Composer(FO1 f1, FO2 f2) : FO1(f1), FO2(f2) { } // ''function call'': nested call of function objects double operator() (double v) { return FO2::operator()(FO1::operator()(v)); } };

T h i s appro ach , h o w e v e r, i s no t re al l y co m m e ndabl e . It pre v e nts u s f ro m co m po si ng a f u ncti o n w i th i tse l f . Inde e d, th e cal l o f

// print sin(sin()) of some values print_values(compose(Sine(),Sine())); // ERROR: duplicate base class name

l e ads to th e i nstanti ati o n o f Composer su ch th at i t de ri v e s tw i ce f ro m cl ass Sine , w h i ch i s i nv al i d.

T h i s du pl i cate base pro bl e m can be e asi l y av o i de d by addi ng an addi ti o nal l e v e l o f

Page 502: CPlusPlus Templates The Complete Guide

i nh e ri tance :

// functors/compose4.hpp template <typename C, int N> class BaseMem : public C { public: BaseMem(C& c) : C(c) { } BaseMem(C const& c) : C(c) { } }; template <typename FO1, typename FO2> class Composer : private BaseMem<FO1,1>, private BaseMem<FO2,2> { public: // constructor: initialize function objects Composer(FO1 f1, FO2 f2) : BaseMem<FO1,1>(f1), BaseMem<FO2,2>(f2) { } // ''function call'': nested call of function objects double operator() (double v) { return BaseMem<FO2,2>::operator() (BaseMem<FO1,1>::operator()(v)); } };

C l e arl y , th e l atte r i m pl e m e ntati o n i s m e ssi e r th an th e o ri g i nal , bu t th i s m ay be an acce ptabl e co st i f i t h e l ps an o pti m i z e r re al i z e th at th e re su l ti ng f u ncto r i s " e m pty ."

Inte re sti ng l y , th e f u ncti o n cal l o pe rato r can be de cl are d v i rtu al . D o i ng so i n a f u ncto r th at parti ci pate s i n a co m po si ti o n m ak e s th e f u ncti o n cal l o pe rato r o f th e re su l ti ng Composer o bj e ct v i rtu al to o . T h i s can l e ad to so m e strang e re su l ts. W e w i l l th e re f o re assu m e th at th e f u ncti o n cal l o pe rato r i s no nv i rtu al i n th e re m ai nde r o f th i s se cti o n.

22.7.2 Mixed Type Composition

A m o re cru ci al i m pro v e m e nt to th e si m pl e Composer te m pl ate i s to al l o w f o r m o re f l e x i bi l i ty i n th e ty pe s i nv o l v e d. W i th th e pre v i o u s i m pl e m e ntati o n, w e al l o w o nl y f u ncto rs th at tak e a double v al u e and re tu rn ano th e r double v al u e . L i f e w o u l d be m o re e l e g ant i f w e co u l d co m po se any m atch i ng ty pe o f f u ncto r. F o r e x am pl e , w e sh o u l d be abl e to co m po se a f u ncto r th at tak e s an int and re tu rns a bool w i th o ne th at tak e s a bool and re tu rns a double. T h i s i s a si tu ati o n i n w h i ch o u r de ci si o n to re q u i re m e m b e r ty pe de f s i n f u ncto r ty pe s co m e s i n h andy .

W i th th e co nv e nti o ns assu m e d by o u r f ram e w o rk , th e co m po si ti o n te m pl ate can be re w ri tte n as f o l l o w s:

Page 503: CPlusPlus Templates The Complete Guide

// functors/compose5.hpp #include "forwardparam.hpp" template <typename C, int N> class BaseMem : public C { public: BaseMem(C& c) : C(c) { } BaseMem(C const& c) : C(c) { } }; template <typename FO1, typename FO2> class Composer : private BaseMem<FO1,1>, private BaseMem<FO2,2> { public: // to let it fit in our framework: enum { NumParams = FO1::NumParams }; typedef typename FO2::ReturnT ReturnT; typedef typename FO1::Param1T Param1T; // constructor: initialize function objects Composer(FO1 f1, FO2 f2) : BaseMem<FO1,1>(f1), BaseMem<FO2,2>(f2) { } // ''function call'': nested call of function objects ReturnT operator() (typename ForwardParamT<Param1T>::Type v) { return BaseMem<FO2,2>::operator() (BaseMem<FO1,1>::operator()(v)); } };

W e re u se d th e ForwardParamT te m pl ate (se e S e cti o n 2 2 .6 .3 o n pag e 4 4 0 ) to av o i d u nne ce ssary co pi e s o f f u ncto r cal l arg u m e nts.

T o u se th e co m po si ti o n te m pl ate w i th o u r Abs and Sine f u ncto rs, th e y h av e to be re w ri tte n to i ncl u de th e appro pri ate ty pe i nf o rm ati o n. T h i s i s do ne as f o l l o w s:

// functors/math2.hpp #include <cmath> #include <cstdlib> class Abs { public: // to fit in the framework: enum { NumParams = 1 }; typedef double ReturnT; typedef double Param1T; // ''function call'': double operator() (double v) const { return std::abs(v); } }; class Sine { public:

Page 504: CPlusPlus Templates The Complete Guide

// to fit in the framework: enum { NumParams = 1 }; typedef double ReturnT; typedef double Param1T; // ''function call'': double operator() (double a) const { return std::sin(a); } };

A l te rnati v e l y , w e can i m pl e m e nt Abs and Sine as te m pl ate s:

// functors/math3.hpp #include <cmath> #include <cstdlib> template <typename T> class Abs { public: // to fit in the framework: enum { NumParams = 1 }; typedef T ReturnT; typedef T Param1T; // ''function call'': T operator() (T v) const { return std::abs(v); } }; template <typename T> class Sine { public: // to fit in the framework: enum { NumParams = 1 }; typedef T ReturnT; typedef T Param1T; // ''function call'': T operator() (T a) const { return std::sin(a); } };

W i th th e l atte r appro ach , u si ng th e se f u ncto rs re q u i re s th e arg u m e nt ty pe s to be pro v i de d e x pl i ci tl y as te m pl ate arg u m e nts. T h e f o l l o w i ng adaptati o n o f o u r sam pl e u se i l l u strate s th e sl i g h tl y m o re cu m be rso m e sy ntax :

// functors/compose5.cpp #include <iostream> #include "math3.hpp" #include "compose5.hpp" #include "composeconv.hpp"

Page 505: CPlusPlus Templates The Complete Guide

template<typename FO> void print_values (FO fo) { for (int i=-2; i<3; ++i) { std::cout << "f(" << i*0.1 << ") = " << fo(i*0.1) << "\n"; } } int main() { // print sin(abs(-0.5)) std::cout << compose(Abs<double>(),Sine<double>())(0.5) << "\n\n"; // print abs() of some values print_values(Abs<double>()); std::cout << '\n'; // print sin() of some values print_values(Sine<double>()); std::cout << '\n'; // print sin(abs()) of some values print_values(compose(Abs<double>(),Sine<double>())); std::cout << '\n'; // print abs(sin()) of some values print_values(compose(Sine<double>(),Abs<double>())); std::cout << '\n'; // print sin(sin()) of some values print_values(compose(Sine<double>(),Sine<double>())); }

22.7.3 Reducing the Number of Parameters

S o f ar w e h av e l o o k e d at a si m pl e f o rm o f f u ncto r co m po si ti o n w h e re o ne f u ncto r tak e s o ne arg u m e nt, and th at arg u m e nt i s ano th e r f u ncto r i nv o cati o n w h i ch i tse l f h as o ne param e te r. C l e arl y , f u ncto rs can h av e m u l ti pl e arg u m e nts, and th e re f o re i t i s u se f u l to al l o w f o r th e co m po si ti o n o f f u ncto rs w i th m u l ti pl e param e te rs. In th i s se cti o n w e di scu ss th e i m pl i cati o n o f al l o w i ng th e f i rst arg u m e nt o f Composer to be a f u ncto r w i th m u l ti pl e param e te rs.

If th e f i rst f u ncto r arg u m e nt o f Composer tak e s m u l ti pl e arg u m e nts, th e re su l ti ng Composer cl ass m u st acce pt m u l ti pl e arg u m e nts to o . T h i s m e ans th at w e h av e to de f i ne m u l ti pl e ParamNT m e m be r ty pe s and w e ne e d to pro v i de a f u ncti o n cal l o pe rato r (o pe rato r ()) w i th th e appro pri ate nu m be r o f param e te rs. T h e l atte r pro bl e m i s no t as h ard to so l v e as i t m ay se e m . F u ncti o n cal l o pe rato rs can be o v e rl o ade d; h e nce w e can j u st pro v i de f u ncti o n cal l o pe rato rs f o r e v e ry nu m be r o f param e te rs u p to a re aso nabl y h i g h nu m be r (an i ndu stri al -stre ng th f u ncto r l i brary m ay g o as h i g h as 2 0 param e te rs). A ny atte m pt to cal l an o v e rl o ade d

Page 506: CPlusPlus Templates The Complete Guide

o pe rato r w i th a nu m be r o f param e te rs th at do e s no t m atch th e nu m be r o f param e te rs o f th e f i rst co m po se d f u ncto r re su l ts i n a transl ati o n (co m pi l ati o n) e rro r, w h i ch i s pe rf e ctl y al l ri g h t. T h e co de m i g h t l o o k as f o l l o w s:

template <typename FO1, typename FO2> class Composer : private BaseMem<FO1,1>, private BaseMem<FO2,2> { public: … // ''function call'' for no arguments: ReturnT operator() () { return BaseMem<FO2,2>::operator() (BaseMem<FO1,1>::operator()()); } // ''function call'' for one argument: ReturnT operator() (typename ForwardParamT<Param1T>::Type v1) { return BaseMem<FO2,2>::operator() (BaseMem<FO1,1>::operator()(v1)); } // ''function call'' for two arguments: ReturnT operator() (typename ForwardParamT<Param1T>::Type v1, typename ForwardParamT<Param2T>::Type v2) { return BaseMem<FO2,2>::operator() (BaseMem<FO1,1>::operator()(v1, v2)); } … };

W e are no w l e f t w i th th e task o f de f i ni ng m e m be rs Param1T , Param2T, and so o n. T h i s task i s m ade m o re co m pl i cate d by th e f act th at th e se ty pe s are u se d i n th e de cl arati o n o f th e v ari o u s f u ncti o n cal l o pe rato rs: T h e se m u st be v al i d e v e n th o u g h th e co m po se d f u ncto rs do no t h av e co rre spo ndi ng param e te rs. [9 ] F o r e x am pl e , i f w e co m po se tw o si ng l e -param e te r f u ncto rs, w e m u st sti l l co m e u p w i th a Param2T ty pe th at m ak e s a v al i d param e te r ty pe . P re f e rabl y , th i s ty pe sh o u l d no t acci de ntal l y m atch ano th e r ty pe u se d i n a cl i e nt pro g ram . F o rtu nate l y , w e al re ady so l v e d th i s pro bl e m w i th FunctorParam te m pl ate . T h e Compose te m pl ate can th e re f o re be e q u i ppe d w i th i ts v ari o u s m e m be r ty pe de f s as f o l l o w s:

[9 ] No te th at th e S F INA E pri nci pl e (se e S e cti o n 8 .3 .1 o n pag e 1 0 6 ) do e s no t appl y h e re be cau se th e se are o rdi nary m e m be r f u ncti o ns and no t m e m be r f u ncti o n te m pl ate s. S F INA E i s base d o n te m pl ate param e te r de du cti o n, w h i ch do e s no t o ccu r f o r o rdi nary m e m be r f u ncti o ns.

template <typename FO1, typename FO2> class Composer : private BaseMem<FO1,1>, private BaseMem<FO2,2> { public: // the return type is straightforward: typedef typename FO2::ReturnT ReturnT;

Page 507: CPlusPlus Templates The Complete Guide

// define Param1T, Param2T, and so on // - use a macro to ease the replication of the parameter type construct #define ComposeParamT(N) \ typedef typename FunctorParam<FO1, N>::Type Param##N##T ComposeParamT(1); ComposeParamT(2); … ComposeParamT(20); #undef ComposeParamT … };

F i nal l y , w e ne e d to add th e Composer co nstru cto rs. T h e y tak e th e tw o f u ncto rs be i ng co m po se d, bu t w e al l o w f o r th e v ari o u s co m bi nati o ns o f const and no n-const f u ncto rs:

template <typename FO1, typename FO2> class Composer : private BaseMem<FO1,1>, private BaseMem<FO2,2> { public: … // constructors: Composer(FO1 const& f1, FO2 const& f2) : BaseMem<FO1,1>(f1), BaseMem<FO2,2>(f2) { } Composer(FO1 const& f1, FO2& f2) : BaseMem<FO1,1>(f1), BaseMem<FO2,2>(f2) { } Composer(FO1& f1, FO2 const& f2) : BaseMem<FO1,1>(f1), BaseMem<FO2,2>(f2) { } Composer(FO1& f1, FO2& f2) : BaseMem<FO1,1>(f1), BaseMem<FO2,2>(f2) { } … };

W i th al l th i s l i brary co de i n pl ace , a pro g ram can no w u se si m pl e co nstru cts, as i l l u strate d i n th e f o l l o w i ng e x am pl e :

// functors/compose6.cpp #include <iostream> #include "funcptr.hpp" #include "compose6.hpp" #include "composeconv.hpp" double add(double a, double b) { return a+b; } double twice(double a) { return 2*a;

Page 508: CPlusPlus Templates The Complete Guide

} int main() { std::cout << "compute (20+7)*2: " << compose(func_ptr(add),func_ptr(twice))(20,7) << '\n'; }

T h e se to o l s can sti l l be re f i ne d i n v ari o u s w ay s. F o r e x am pl e , i t i s u se f u l to e x te nd th e compose te m pl ate to h andl e f u ncti o n po i nte rs di re ctl y (m ak i ng th e u se o f func_ptr i n o u r l ast e x am pl e u nne ce ssary ). H o w e v e r, i n th e i nte re st o f bre v i ty , w e pre f e r to l e av e su ch i m pro v e m e nts to th e i nte re ste d re ade r.

Page 509: CPlusPlus Templates The Complete Guide

22.8 Value Binders

O f te n, a f u ncto r w i th m u l ti pl e param e te rs re m ai ns u se f u l w h e n o ne o f th e param e te rs i s b ound to a spe ci f i c v al u e . F o r e x am pl e , a si m pl e Min f u ncto r te m pl ate su ch as

// functors/min.hpp template <typename T> class Min { public: typedef T ReturnT; typedef T Param1T; typedef T Param2T; enum { NumParams = 2 }; ReturnT operator() (Param1T a, Param2T b) { return a<b ? b : a; } };

can be u se d to bu i l d a ne w Clamp f u ncto r th at be h av e s l i k e Min w i th o ne o f i ts param e te rs bo u nd to a ce rtai n co nstant. T h e co nstant co u l d be spe ci f i e d as a te m pl ate arg u m e nt o r as a ru n-ti m e arg u m e nt. F o r e x am pl e , w e can w ri te th e ne w f u ncto r as f o l l o w s:

// functors/clamp.hpp template <typename T, T max_result> class Clamp : private Min<T> { public: typedef T ReturnT; typedef T Param1T; enum { NumParams = 1 }; ReturnT operator() (Param1T a) { return Min<T>::operator() (a, max_result); } };

A s w i th co m po si ti o n, i t i s v e ry co nv e ni e nt to h av e so m e te m pl ate th at au to m ate s th e task o f bi ndi ng a f u ncto r param e te r av ai l abl e , e v e n th o u g h i t do e sn' t tak e v e ry m u ch co de to do so m anu al l y .

22.8.1 Selecting the Binding

A b i nde r bi nds a parti cu l ar param e te r o f a parti cu l ar f u ncto r to a parti cu l ar v al u e . E ach o f th e se aspe cts can be se l e cte d at ru n ti m e (u si ng f u ncti o n cal l arg u m e nts) o r at co m pi l e ti m e (u si ng te m pl ate arg u m e nts).

Page 510: CPlusPlus Templates The Complete Guide

F o r e x am pl e , th e f o l l o w i ng te m pl ate se l e cts e v e ry th i ng stati cal l y (th at i s, at co m pi l e ti m e ):

template<typename F, int P, int V> class BindIntStatically; // F is the functor type // P is the parameter to bind // V is the value to be bound

E ach o f th e th re e bi ndi ng aspe cts (f u ncto r, bo u nd param e te r, and bo u nd v al u e ) can i nste ad be se l e cte d dy nam i cal l y w i th v ari o u s de g re e s o f co nv e ni e nce .

P e rh aps th e l e ast co nv e ni e nt i s to m ak e th e se l e cti o n o f w h i ch param e te r to bi nd dy nam i c. P re su m abl y th i s w o u l d i nv o l v e l arg e switch state m e nts th at de l e g ate th e f u ncto r cal l to di f f e re nt cal l s to th e u nde rl y i ng f u ncto r de pe ndi ng o n a ru n-ti m e v al u e . T h i s m ay , f o r e x am pl e l o o k as f o l l o w s:

… switch (this->param_num) { case 1: return F::operator()(v, p1, p2); case 2: return F::operator()(p1, v, p2); case 3: return F::operator()(p1, p2, v); default: return F::operator()(p1, p2); // or an error? }

O f th e th re e bi ndi ng aspe cts, th i s i s pro babl y th e o ne th at ne e ds to be co m e dy nam i c th e l e ast. In w h at f o l l o w s, w e th e re f o re k e e p th i s as a te m pl ate param e te r so th at i t i s a stati c se l e cti o n.

T o m ak e th e se l e cti o n o f th e f u ncto r dy nam i c, i t i s su f f i ci e nt to add a co nstru cto r th at acce pts a f u ncto r to o u r bi nde r. S i m i l arl y , w e can al so pass th e bo u nd v al u e to th e co nstru cto r, bu t th i s re q u i re s u s to pro v i de sto rag e i n th e bi nde r to h o l d th e bo u nd v al u e . T h e f o l l o w i ng tw o h e l pe r te m pl ate s can be u se d to h o l d bo u nd v al u e s at co m pi l e ti m e and ru n ti m e re spe cti v e l y :

// functors/boundval.hpp #include "typeop.hpp" template <typename T> class BoundVal { private: T value; public: typedef T ValueT; BoundVal(T v) : value(v) {

Page 511: CPlusPlus Templates The Complete Guide

} typename TypeOp<T>::RefT get() { return value; } }; template <typename T, T Val> class StaticBoundVal { public: typedef T ValueT; T get() { return Val; } };

A g ai n, w e re l y o n th e e m pty base cl ass o pti m i z ati o n (se e S e cti o n 1 6 .2 o n pag e 2 8 9 ) to av o i d u nne ce ssary o v e rh e ad i f th e f u ncto r o r th e bo u nd v al u e re pre se ntati o n i s state l e ss. T h e be g i nni ng o f o u r Binder te m pl ate de si g n th e re f o re l o o k s as f o l l o w s:

// functors/binder1.hpp template <typename FO, int P, typename V> class Binder : private FO, private V { public: // constructors: Binder(FO& f): FO(f) {} Binder(FO& f, V& v): FO(f), V(v) {} Binder(FO& f, V const& v): FO(f), V(v) {} Binder(FO const& f): FO(f) {} Binder(FO const& f, V& v): FO(f), V(v) {} Binder(FO const& f, V const& v): FO(f), V(v) {} template<class T> Binder(FO& f, T& v): FO(f), V(BoundVal<T>(v)) {} template<class T> Binder(FO& f, T const& v): FO(f), V(BoundVal<T const>(v)) {} … };

No te th at, i n addi ti o n to co nstru cto rs tak i ng i nstance s o f o u r h e l pe r te m pl ate s, w e al so pro v i de co nstru cto r te m pl ate s th at au to m ati cal l y w rap a g i v e n bo u nd v al u e i n a BoundVal o bj e ct.

22.8.2 Bound Signature

D e te rm i ni ng th e ParamNT ty pe s f o r th e Binder te m pl ate i s h arde r th an i t w as f o r th e Composer te m pl ate be cau se w e canno t j u st tak e o v e r th e ty pe s o f th e f u ncto r o n w h i ch w e bu i l d. Inste ad, be cau se th e param e te r th at i s bo u nd i s no l o ng e r a param e te r i n th e ne w f u ncto r, w e m u st dro p th e co rre spo ndi ng ParamNT and sh i f t th e su bse q u e nt ty pe s by o ne po si ti o n.

T o k e e p th i ng s m o du l ar, w e can i ntro du ce a se parate te m pl ate th at pe rf o rm s th e

Page 512: CPlusPlus Templates The Complete Guide

se l e cti v e sh i f ti ng o pe rati o n:

// functors/binderparams.hpp #include "ifthenelse.hpp" template<typename F, int P> class BinderParams { public: // there is one less parameter because one is bound: enum { NumParams = F::NumParams-1 }; #define ComposeParamT(N) \ typedef typename IfThenElse<(N<P), FunctorParam<F, N>, \ FunctorParam<F, N+1> \ >::ResultT::Type \ Param##N##T ComposeParamT(1); ComposeParamT(2); ComposeParamT(3); … #undef ComposeParamT };

T h i s can be u se d i n th e Binder te m pl ate as f o l l o w s:

// functors/binder2.hpp template <typename FO, int P, typename V> class Binder : private FO, private V { public: // there is one less parameter because one is bound: enum { NumParams = FO::NumParams-1 }; // the return type is straightforward: typedef typename FO::ReturnT ReturnT; // the parameter types: typedef BinderParams<FO, P> Params; #define ComposeParamT(N) \ typedef typename \ ForwardParamT<typename Params::Param##N##T>::Type \ Param##N##T ComposeParamT(1); ComposeParamT(2); ComposeParamT(3); … #undef ComposeParamT … };

A s u su al , w e u se th e ForwardParamT te m pl ate to av o i d u nne ce ssary co py i ng o f arg u m e nts.

22.8.3 Argument Selection

T o co m pl e te th e Binder te m pl ate w e are l e f t w i th th e pro bl e m o f i m pl e m e nti ng

Page 513: CPlusPlus Templates The Complete Guide

th e f u ncti o n cal l o pe rato r. A s w i th Composer w e are g o i ng to o v e rl o ad th i s o pe rato r f o r v ary i ng nu m be rs o f f u ncto r cal l arg u m e nts. H o w e v e r, th e pro bl e m h e re i s co nsi de rabl y h arde r th an f o r co m po si ti o n be cau se th e arg u m e nt to be passe d to th e u nde rl y i ng f u ncto r can be o ne o f th re e di f f e re nt v al u e s:

• T h e co rre spo ndi ng param e te r o f th e bo u nd f u ncto r • T h e bo u nd v al u e • T h e param e te r o f th e bo u nd f u ncto r th at i s o ne po si ti o n to th e l e f t o f th e

arg u m e nt w e m u st pass

W h i ch o f th e th re e v al u e s w e se l e ct de pe nds o n th e v al u e o f P and th e po si ti o n o f th e arg u m e nt w e are se l e cti ng .

O u r i de a to ach i e v e th e de si re d re su l t i s to w ri te a pri v ate i nl i ne m e m be r f u ncti o n th at acce pts (by re f e re nce ) th e th re e po ssi bl e v al u e s bu t re tu rns (sti l l by re f e re nce ) th e o ne th at i s appro pri ate f o r th at arg u m e nt po si ti o n. B e cau se th i s m e m be r f u ncti o n de pe nds o n w h i ch arg u m e nt w e ' re se l e cti ng , w e i ntro du ce i t as a stati c m e m be r o f a ne ste d cl ass te m pl ate . T h i s appro ach e nabl e s u s to w ri te a f u ncti o n cal l o pe rato r as f o l l o w s (h e re sh o w n f o r bi ndi ng a f o u r-param e te r f u ncto r; o th e rs are si m i l ar):

// functors/binder3.hpp template <typename FO, int P, typename V> class Binder : private FO, private V { public: … ReturnT operator() (Param1T v1, Param2T v2, Param3T v3) { return FO::operator()(ArgSelect<1>::from(v1,v1,V::get()), ArgSelect<2>::from(v1,v2,V::get()), ArgSelect<3>::from(v2,v3,V::get()), ArgSelect<4>::from(v3,v3,V::get())); } … };

No te th at f o r th e f i rst and l ast arg u m e nt, o nl y tw o arg u m e nt v al u e s are po ssi bl e : th e f i rst o r l ast param e te r o f th e o pe rato r, o r th e bo u nd v al u e . If A i s th e po si ti o n o f th e arg u m e nt i n th e cal l to th e u nde rl y i ng f u ncto r (1 th ro u g h 3 i n th e e x am pl e ), th e n th e co rre spo ndi ng param e te r i s se l e cte d w h e n A-P i s l e ss th an z e ro , th e bo u nd v al u e i s se l e cte d w h e n A-P i s e q u al to z e ro , and a param e te r to th e l e f t o f th e arg u m e nt po si ti o n i s se l e cte d w h e n A-P i s stri ctl y po si ti v e . T h i s o bse rv ati o n j u sti f i e s th e de f i ni ti o n o f a h e l pe r te m pl ate th at se l e cts o ne o f th re e ty pe s base d o n th e si g n o f a no nty pe te m pl ate arg u m e nt:

// functors/signselect.hpp

Page 514: CPlusPlus Templates The Complete Guide

#include "ifthenelse.hpp" template <int S, typename NegT, typename ZeroT, typename PosT> struct SignSelectT { typedef typename IfThenElse<(S<0), NegT, typename IfThenElse<(S>0), PosT, ZeroT >::ResultT >::ResultT ResultT; };

W i th th i s i n pl ace , w e are re ady to de f i ne th e m e m be r cl ass te m pl ate ArgSelect:

// functors/binder4.hpp template <typename FO, int P, typename V> class Binder : private FO, private V { … private: template<int A> class ArgSelect { public: // type if we haven't passed the bound argument yet: typedef typename TypeOp< typename IfThenElse<(A<=Params::NumParams), FunctorParam<Params, A>, FunctorParam<Params, A-1> >::ResultT::Type>::RefT NoSkipT; // type if we're past the bound argument: typedef typename TypeOp< typename IfThenElse<(A>1), FunctorParam<Params, A-1>, FunctorParam<Params, A> >::ResultT::Type>::RefT SkipT; // type of bound argument: typedef typename TypeOp<typename V::ValueT>::RefT BindT; // three selection cases implemented through different classes: class NoSkip { public: static NoSkipT select (SkipT prev_arg, NoSkipT arg, BindT bound_val) { return arg; } }; class Skip { public: static SkipT select (SkipT prev_arg, NoSkipT arg, BindT bound_val) { return prev_arg; }

Page 515: CPlusPlus Templates The Complete Guide

}; class Bind { public: static BindT select (SkipT prev_arg, NoSkipT arg, BindT bound_val) { return bound_val; } }; // the actual selection function: typedef typename SignSelectT<A-P, NoSkipT, BindT, SkipT>::ResultT ReturnT; typedef typename SignSelectT<A-P, NoSkip, Bind, Skip>::ResultT SelectedT; static ReturnT from (SkipT prev_arg, NoSkipT arg, BindT bound_val) { return SelectedT::select (prev_arg, arg, bound_val); } }; };

T h i s i s adm i tte dl y am o ng th e m o st co m pl i cate d co de se g m e nts i n th i s bo o k . T h e from m e m be r f u ncti o n i s th e o ne cal l e d f ro m th e f u ncto r cal l o pe rato rs. P art o f th e di f f i cu l ty l i e s i n th e se l e cti o n o f th e ri g h t param e te r ty pe s f ro m w h i ch th e arg u m e nt i s se l e cte d: SkipT and NoSkipT al so i nco rpo rate th e co nv e nti o n w e u se f o r th e f i rst and l ast arg u m e nt (th at i s, re pe ati ng v1 and v4 i n th e o pe rato r i l l u strate d e arl i e r). W e u se th e TypeOp<>::RefT co nstru ct to de f i ne th e se ty pe s: W e co u l d j u st cre ate a re f e re nce ty pe u si ng th e & sy m bo l , bu t m o st co m pi l e rs canno t h andl e " re f e re nce s to re f e re nce s" y e t. T h e se l e cti o n f u ncti o ns th e m se l v e s are rath e r tri v i al , bu t th e y w e re e ncapsu l ate d i n m e m b e r ty pe s NoSkip , Skip, and Bind to di spatch stati cal l y th e appro pri ate f u ncti o n e asi l y . B e cau se th e se f u ncti o ns are th e m se l v e s si m pl e i nl i ne f o rw ardi ng f u ncti o ns, a g o o d o pti m i z i ng co m pi l e r sh o u l d be abl e to " se e th ro u g h " i t al l and g e ne rate ne ar-o pti m i m al co de . In practi ce , o nl y th e be st o pti m i z e rs av ai l abl e at th e ti m e o f th i s w ri ti ng pe rf o rm e nti re l y sati f acto ri l y i n th e pe rf o rm ance are a. H o w e v e r, m o st o th e r co m pi l e rs sti l l do a re aso nabl e j o b o f o pti m i z i ng u se s o f Binder.

P u tti ng i t al l to g e th e r, o u r co m pl e te Binder te m pl ate i s i m pl e m e nte d as f o l l o w s:

// functors/binder5.hpp #include "ifthenelse.hpp" #include "boundval.hpp" #include "forwardparam.hpp" #include "functorparam.hpp" #include "binderparams.hpp" #include "signselect.hpp" template <typename FO, int P, typename V> class Binder : private FO, private V {

Page 516: CPlusPlus Templates The Complete Guide

public: // there is one less parameter because one is bound: enum { NumParams = FO::NumParams-1 }; // the return type is straightforward: typedef typename FO::ReturnT ReturnT; // the parameter types: typedef BinderParams<FO, P> Params; #define ComposeParamT(N) \ typedef typename \ ForwardParamT<typename Params::Param##N##T>::Type \ Param##N##T ComposeParamT(1); ComposeParamT(2); ComposeParamT(3); … #undef ComposeParamT // constructors: Binder(FO& f): FO(f) {} Binder(FO& f, V& v): FO(f), V(v) {} Binder(FO& f, V const& v): FO(f), V(v) {} Binder(FO const& f): FO(f) {} Binder(FO const& f, V& v): FO(f), V(v) {} Binder(FO const& f, V const& v): FO(f), V(v) {} template<class T> Binder(FO& f, T& v): FO(f), V(BoundVal<T>(v)) {} template<class T> Binder(FO& f, T const& v): FO(f), V(BoundVal<T const>(v)) {} // ''function calls'': ReturnT operator() () { return FO::operator()(V::get()); } ReturnT operator() (Param1T v1) { return FO::operator()(ArgSelect<1>::from(v1,v1,V::get()), ArgSelect<2>::from(v1,v1,V::get())); } ReturnT operator() (Param1T v1, Param2T v2) { return FO::operator()(ArgSelect<1>::from(v1,v1,V::get()), ArgSelect<2>::from(v1,v2,V::get()), ArgSelect<3>::from(v2,v2,V::get())); } ReturnT operator() (Param1T v1, Param2T v2, Param3T v3) { return FO::operator()(ArgSelect<1>::from(v1,v1,V::get()), ArgSelect<2>::from(v1,v2,V::get()), ArgSelect<3>::from(v2,v3,V::get()), ArgSelect<4>::from(v3,v3,V::get())); } … private: template<int A> class ArgSelect { public: // type if we haven't passed the bound argument yet: typedef typename TypeOp< typename IfThenElse<(A<=Params::NumParams), FunctorParam<Params, A>, FunctorParam<Params, A-1> >::ResultT::Type>::RefT

Page 517: CPlusPlus Templates The Complete Guide

NoSkipT; // type if we're past the bound argument: typedef typename TypeOp< typename IfThenElse<(A>1), FunctorParam<Params, A-1>, FunctorParam<Params, A> >::ResultT::Type>::RefT SkipT; // type of bound argument: typedef typename TypeOp<typename V::ValueT>::RefT BindT; // three selection cases implemented through different classes: class NoSkip { public: static NoSkipT select (SkipT prev_arg, NoSkipT arg, BindT bound_val) { return arg; } }; class Skip { public: static SkipT select (SkipT prev_arg, NoSkipT arg, BindT bound_val) { return prev_arg; } }; class Bind { public: static BindT select (SkipT prev_arg, NoSkipT arg, BindT bound_val) { return bound_val; } }; // the actual selection function: typedef typename SignSelectT<A-P, NoSkipT, BindT, SkipT>::ResultT ReturnT; typedef typename SignSelectT<A-P, NoSkip, Bind, Skip>::ResultT SelectedT; static ReturnT from (SkipT prev_arg, NoSkipT arg, BindT bound_val) { return SelectedT::select (prev_arg, arg, bound_val); } }; };

22.8.4 Convenience Functions

A s w i th th e co m po si ti o n te m pl ate s, i t i s u se f u l to w ri te f u ncti o n te m pl ate s th at m ak e i t e asi e r to e x pre ss th e bi ndi ng o f a v al u e to a f u ncto r param e te r. T h e de f i ni ti o n o f su ch a te m pl ate i s m ade a l i ttl e h arde r by th e ne e d to e x pre ss th e ty pe o f th e bo u nd v al u e :

// functors/bindconv.hpp

Page 518: CPlusPlus Templates The Complete Guide

#include "forwardparam.hpp" #include "functorparam.hpp" template <int P, // position of the bound parameter typename FO> // functor whose parameter is bound inline Binder<FO,P,BoundVal<typename FunctorParam<FO,P>::Type> > bind (FO const& fo, typename ForwardParamT <typename FunctorParam<FO,P>::Type>::Type val) { return Binder<FO, P, BoundVal<typename FunctorParam<FO,P>::Type> >(fo, BoundVal<typename FunctorParam<FO,P>::Type>(val) ); }

T h e f i rst te m pl ate param e te r i s no t de du ci bl e : It m u st be spe ci f i e d e x pl i ci tl y w h e n u si ng th e bind() te m pl ate . T h e f o l l o w i ng e x am pl e i l l u strate s th i s:

// functors/bindtest.cpp #include <string> #include <iostream> #include "funcptr.hpp" #include "binder5.hpp" #include "bindconv.hpp" bool func (std::string const& str, double d, float f) { std::cout << str << ": " << d << (d<f? "<": ">=") << f << '\n'; return d<f; } int main() { bool result = bind<1>(func_ptr(func), "Comparing")(1.0, 2.0); std::cout << "bound function returned " << result << '\n'; }

It m ay be te m pti ng to si m pl i f y th e bind te m pl ate by addi ng a de du ci bl e te m pl ate param e te r f o r th e bo u nd v al u e , th e re by av o i di ng th e cu m be rso m e e x pre ssi o n o f th e ty pe , as do ne h e re . H o w e v e r, th i s o f te n l e ads to di f f i cu l ti e s i n si tu ati o ns l i k e th i s e x am pl e , i n w h i ch a l i te ral o f ty pe double (2.0) i s passe d to a param e te r o f a co m pati bl e bu t di f f e re nt ty pe float.

It i s al so o f te n co nv e ni e nt to be abl e to bi nd a f u ncti o n (passe d as a f u ncti o n po i nte r) di re ctl y . T h e de f i ni ti o ns o f th e re su l ti ng bindfp() te m pl ate s i s o nl y sl i g h tl y m o re co m pl i cate d th an th at o f th e bind te m pl ate . H e re i s th e co de f o r

Page 519: CPlusPlus Templates The Complete Guide

th e case o f a f u ncti o n w i th tw o param e te rs:

// functors/bindfp2.hpp // convenience function to bind a function pointer with two parameters template<int PNum, typename RT, typename P1, typename P2> inline Binder<FunctionPtr<RT,P1,P2>, PNum, BoundVal<typename FunctorParam<FunctionPtr<RT,P1,P2>, PNum >::Type > > bindfp (RT (*fp)(P1,P2), typename ForwardParamT <typename FunctorParam<FunctionPtr<RT,P1,P2>, PNum >::Type >::Type val) { return Binder<FunctionPtr<RT,P1,P2>, PNum, BoundVal <typename FunctorParam<FunctionPtr<RT,P1,P2>, PNum >::Type > >(func_ptr(fp), BoundVal<typename FunctorParam <FunctionPtr<RT,P1,P2>, PNum >::Type >(val) ); }

Page 520: CPlusPlus Templates The Complete Guide

Functor Operations: A Complete Implementation

T o i l l u strate th e o v e ral l e f f e ct ach i e v e d by o u r so ph i sti cate d tre atm e nt o f f u ncto r co m po si ti o n and v al u e bi ndi ng , w e pro v i de h e re a co m pl e te i m pl e m e ntati o n o f th e se o pe rati o ns f o r f u ncto rs w i th u p to th re e param e te rs. (It i s strai g h tf o rw ard to e x te nd th i s to a do z e n param e te rs o r so , bu t w e pre f e r to k e e p th e pri nte d co de re l ati v e l y co nci se .)

L e t' s f i rst l o o k at so m e sam pl e cl i e nt co de :

// functors/functorops.cpp #include <iostream> #include <string> #include <typeinfo> #include "functorops.hpp" bool compare (std::string debugstr, double v1, float v2) { if (debugstr != "") { std::cout << debugstr << ": " << v1 << (v1<v2? '<' : '>') << v2 << '\n'; } return v1<v2; } void print_name_value (std::string name, double value) { std::cout << name << ": " << value << '\n'; } double sub (double a, double b) { return a-b; } double twice (double a) { return 2*a; } int main() { using std::cout; // demonstrate composition: cout << "Composition result: " << compose(func_ptr(sub), func_ptr(twice))(3.0, 7.0) << '\n'; // demonstrate binding: cout << "Binding result: " << bindfp<1>(compare, "main()->compare()")(1.02, 1.03)

Page 521: CPlusPlus Templates The Complete Guide

<< '\n'; cout << "Binding output: "; bindfp<1>(print_name_value, "the ultimate answer to life")(42); // combine composition and binding: cout << "Mixing composition and binding (bind<1>): " << bind<1>(compose(func_ptr(sub),func_ptr(twice)), 7.0)(3.0) << '\n'; cout << "Mixing composition and binding (bind<2>): " << bind<2>(compose(func_ptr(sub),func_ptr(twice)), 7.0)(3.0) << '\n'; }

T h e pro g ram h as th e f o l l o w i ng o u tpu t:

Composition result: -8 Binding result: main()->compare(): 1.02<1.03 1 Binding output: the ultimate answer to life: 42 Mixing composition and binding (bind<1>): 8 Mixing composition and binding (bind<2>): -8

T h e m ai n co ncl u si o n th at can be draw n f ro m th i s l i ttl e pro g ram i s th at us i ng th e f u ncto r o pe rati o ns de v e l o pe d i n th i s se cti o n i s v e ry si m pl e (e v e n th o u g h i m p l e m e nt i ng th e m w as no e asy task ).

No te al so h o w th e bi ndi ng and th e co m po si ng te m pl ate s i nte ro pe rate se e m l e ssl y . T h e co re f aci l i ty th at e nabl e s th i s i s th e sm al l se t o f co nv e nti o ns w e e stabl i sh e d f o r f u ncto rs i n S e cti o n 2 2 .6 .1 o n pag e 4 3 6 . T h i s i s no t u nl i k e th e re q u i re m e nts e stabl i sh e d f o r i te rato rs i n th e C + + standard l i brary . F u ncto rs th at do no t f o l l o w o u r co nv e nti o ns are e asi l y w rappe d i n adapte r cl asse s (as i l l u strate d by o u r func_ptr() adaptati o n te m pl ate s). F u rth e rm o re , o u r de si g n al l o w s state -o f -th e -art co m pi l e rs to av o i d any u nne ce ssary ru n-ti m e pe nal ty co m pare d to h and-co de d f u ncto rs.

F i nal l y , th e co nte nts o f functorops.hpp, w h i ch sh o w s w h i ch h e ade r f i l e s are ne ce ssary to be abl e to co m pi l e th e pre v i o u s e x am pl e , l o o k s as f o l l o w s:

// functors/functorops.hpp #ifndef FUNCTOROPS_HPP #define FUNCTOROPS_HPP // define func_ptr(), FunctionPtr, and FunctionPtrT #include "funcptr.hpp" // define Composer<> #include "compose6.hpp"

Page 522: CPlusPlus Templates The Complete Guide

// define convenience function compose() #include "composeconv.hpp" // define Binder<> // - includes boundval.hpp to define BoundVal<> and StaticBoundVal<> // - includes forwardparam.hpp to define ForwardParamT<> // - includes functorparam.hpp to define FunctorParam<> // - includes binderparams.hpp to define BinderParams<> // - includes signselect.hpp to define SignSelectT<> #include "binder5.hpp" // define convenience functions bind() and bindfp() #include "bindconv.hpp" #include "bindfp1.hpp" #include "bindfp2.hpp" #include "bindfp3.hpp" #endif // FUNCTOROPS_HPP

Page 523: CPlusPlus Templates The Complete Guide

22.10 Afternotes

T h e S T L part o f th e C + + standard l i brary u se s th e co nce pt o f f u ncto rs. F o r e x am pl e , al l al g o ri th m s u se f u ncto rs to cu sto m i z e th e i r e x act be h av i o r. M any o f th e se f u ncto rs are so -cal l e d p r e di c a t e s . P re di cate s are f u ncti o ns o r f u ncti o n o bj e cts th at re tu rn a B o o l e an v al u e (a v al u e th at i s co nv e rti bl e to bool). T h e pre di cate s, i n g e ne ral , sh o u l d be pu re f u ncto rs; o th e rw i se , u ne x pe cte d re su l ts m ay o ccu r (se e S e cti o n 8 .1 .4 o f [J o su tti sS tdL i b]).

T h e C + + standard l i brary al so pro v i de s se v e ral standard f u ncto rs and adapte rs f o r co m po si ti o n. In f act, f o r e v e ry co m m o n u nary and bi nary o pe rato r a f u ncti o n o bj e ct i s pro v i de d. S e e S e cti o ns 8 .2 and 8 .3 o f [J o su tti sS tdL i b] f o r de tai l s. H o w e v e r, no te th at th e C + + standard l i brary do e s no t pro v i de e no u g h adapte rs to su ppo rt e v e ry f u ncti o nal be h av i o r as a co m bi nati o n o f f u ncti o n o bj e cts. F o r e x am pl e , i t i s no t po ssi bl e to co m bi ne th e re su l ts o f tw o u nary o pe rati o ns to f o rm u l ate a cri te ri o n su ch as " th i s a nd th at." T h e B o o st re po si to ry o f C + + l i brari e s pro v i de s su ppl e m e ntary adapte rs th at f i l l th i s g ap (se e [B o o stC o m po se ]).

Page 524: CPlusPlus Templates The Complete Guide

Appendix A. The One-Definition Rule

A f f e cti o nate l y k no w n as th e O D R , th e one -de f i ni t i on r ul e i s a co rne rsto ne f o r th e w e l l -f o rm e d stru ctu ri ng o f C + + pro g ram s. T h e m o st co m m o n co nse q u e nce s o f th e O D R are si m pl e e no u g h to re m e m b e r and appl y : D e f i ne no ni nl i ne f u ncti o ns e x actl y o nce acro ss al l f i l e s, and de f i ne cl asse s and i nl i ne f u ncti o ns at m o st o nce pe r transl ati o n u ni t, m ak i ng su re th at al l de f i ni ti o ns f o r th e sam e e nti ty are i de nti cal .

H o w e v e r, th e de v i l i s i n th e de tai l s, and w h e n co m bi ne d w i th te m pl ate i nstanti ati o n, th e se de tai l s can be dau nti ng . T h i s appe ndi x i s m e ant to pro v i de a co m pre h e nsi v e o v e rv i e w o f th e O D R f o r th e i nte re ste d re ade r. W e al so i ndi cate w h e n spe ci f i c re l ate d i ssu e s are e x po u nde d o n i n th e m ai n te x t.

Page 525: CPlusPlus Templates The Complete Guide

A.1 Translation Units

In practi ce w e w ri te C + + pro g ram s by f i l l i ng f i l e s w i th " co de ." H o w e v e r, th e bo u ndary se t by a f i l e i s no t te rri bl y i m po rtant i n th e co nte x t o f th e O D R . Inste ad, w h at m atte rs are so -cal l e d t r a ns l a t i on uni t s . E sse nti al l y , a transl ati o n u ni t i s th e re su l t o f appl y i ng th e pre pro ce sso r to a f i l e y o u f e e d to y o u r co m pi l e r. T h e pre pro ce sso r dro ps se cti o ns o f co de no t se l e cte d by co ndi ti o nal co m pi l ati o n di re cti v e s (#if, #ifdef, and f ri e nds), dro ps co m m e nts, i nse rts #included f i l e s (re cu rsi v e l y ), and e x pands m acro s.

H e nce , as f ar as th e O D R i s co nce rne d, h av i ng th e f o l l o w i ng tw o f i l e s

// File header.hpp: #ifdef DO_DEBUG #define debug(x) std::cout << x << '\n' #else #define debug(x) #endif void debug_init(); // File myprog.cpp: #include "header.hpp" int main() { debug_init(); debug("main()"); }

i s e q u i v al e nt to th e f o l l o w i ng si ng l e f i l e :

// File myprog.cpp: void debug_init(); int main() { debug_init(); }

C o nne cti o ns acro ss transl ati o n u ni t bo u ndari e s are e stabl i sh e d by h av i ng co rre spo ndi ng de cl arati o ns w i th e x te rnal l i nk ag e i n tw o transl ati o n u ni ts (f o r e x am pl e , tw o de cl arati o ns o f th e g l o bal f u ncti o n debug_init()) o r by arg u m e nt-de pe nde nt l o o k u p du ri ng th e i nstantati o n o f export e d te m pl ate s.

No te th at th e co nce pt o f a transl ati o n u ni t i s a l i ttl e m o re abstract th an j u st " a pre pro ce sse d f i l e ." F o r e x am pl e , i f w e w e re to f e e d a pre pro ce sse d f i l e tw i ce to a co m pi l e r to f o rm a si ng l e pro g ram , i t w o u l d bri ng i nto th e pro g ram tw o di sti nct

Page 526: CPlusPlus Templates The Complete Guide

transl ati o n u ni ts (th e re i s no po i nt i n do i ng so , h o w e v e r).

Page 527: CPlusPlus Templates The Complete Guide

A.2 Declarations and Definitions

T h e te rm s de c l a r a t i on and de f i ni t i on are o f te n u se d i nte rch ang e abl y i n co m m o n " pro g ram m e r tal k ." In th e co nte x t o f th e O D R , h o w e v e r, th e e x act m e ani ng o f th e se w o rds i s i m po rtant. [1]

[1] W e al so th i nk i t' s a g o o d h abi t to h andl e th e te rm s care f u l l y w h e n e x ch ang i ng i de as abo u t C o r C + + . W e do so th ro u g h o u t th i s bo o k .

A de cl arati o n i s a C + + co nstru ct th at i ntro du ce s o r re i ntro du ce s a nam e i n y o u r pro g ram . A de cl arati o n can al so be a de f i ni ti o n, de pe ndi ng o n w h i ch e nti ty i t i ntro du ce s and h o w i t i ntro du ce s i t:

• Namespaces and namespace aliases: T h e de cl arati o ns o f nam e space s and th e i r al i ase s are al w ay s al so de f i ni ti o ns, al th o u g h th e te rm de f i ni t i on i s u nu su al i n th i s co nte x t be cau se th e l i st o f m e m b e rs o f a nam e space can be " e x te nde d" at a l ate r ti m e (u nl i k e cl asse s and e nu m e rati o n ty pe s f o r e x am pl e ).

• C lasses, class t emplat es, f u nct io ns, f u nct io n t emplat es, memb er f u nct io ns, and memb er f u nct io n t emplat es: T h e de cl arati o n i s a de f i ni ti o n i f and o nl y i f th e de cl arati o n i ncl u de s a brace -e ncl o se d bo dy asso ci ate d w i th th e nam e . T h i s ru l e i ncl u de s u ni o ns, o pe rato rs, m e m b e r o pe rato rs, stati c m e m b e r f u ncti o ns, co nstru cto rs and de stru cto rs, and e x pl i ci t spe ci al i z ati o ns o f te m pl ate v e rsi o ns o f su ch th i ng s (th at i s, any cl ass-l i k e and f u ncti o n-l i k e e nti ty ).

• E nu mer at io ns: T h e de cl arati o n i s a de f i ni ti o n i f and o nl y i f i t i ncl u de s th e brace -e ncl o se d l i st o f e nu m e rato rs.

• L o cal v ar iab les and no nst at ic dat a memb er s: T h e se e nti ti e s can al w ay s be tre ate d as de f i ni ti o ns, al th o u g h th e di sti ncti o n rare l y m atte rs.

• Glo b al v ar iab les: If th e de cl arati o n i s no t di re ctl y pre ce de d by a k e y w o rd extern o r i f i t h as an i ni ti al i z e r, th e de cl arati o n o f a g l o bal v ari abl e i s al so a de f i ni ti o n o f th at v ari abl e . O th e rw i se , i t i s no t a de f i ni ti o n.

• S t at ic dat a memb er s: T h e de cl arati o n i s a de f i ni ti o n i f and o nl y i f i t appe ars o u tsi de th e cl ass o r cl ass te m pl ate o f w h i ch i t i s a m e m b e r.

• T y pedef s, u sing -declar at io ns, and u sing -dir ect iv es: T h e se are ne v e r de f i ni ti o ns, al th o u g h ty pe de f s can be co m bi ne d w i th cl ass o r u ni o n de f i ni ti o ns.

• E x plicit inst ant iat io n dir ect iv es: W e can co nsi de r th e m to be de f i ni ti o ns.

Page 528: CPlusPlus Templates The Complete Guide
Page 529: CPlusPlus Templates The Complete Guide

A.3 The One-Definition Rule in Detail

A s w e i m pl i e d i n th e i ntro du cti o n to th i s appe ndi x , th e re are m any de tai l s to th e actu al ru l e . W e o rg ani z e th e ru l e ' s co nstrai nts by th e i r sco pe .

A.3.1 One-per-Program Constraints

T h e re can be at m o st o ne de f i ni ti o n o f th e f o l l o w i ng i te m s pe r pro g ram :

• No ni nl i ne f u ncti o ns and no ni nl i ne m e m be r f u ncti o ns • V ari abl e s w i th e x te rnal l i nk ag e (e sse nti al l y , v ari abl e s de cl are d i n a

nam e space sco pe o r i n th e g l o bal sco pe , and w i th th e static spe ci f i e r) • S tati c data m e m b e rs • No ni nl i ne f u ncti o n te m pl ate s, no ni nl i ne m e m be r f u ncti o n te m pl ate s, and

no ni nl i ne m e m b e rs o f cl ass te m pl ate s w h e n th e y are de cl are d w i th export

• S tati c data m e m b e rs o f cl ass te m pl ate s w h e n th e y are de cl are d w i th export:

F o r e x am pl e , a C + + pro g ram co nsi sti ng o f th e f o l l o w i ng tw o transl ati o n u ni ts i s i nv al i d [2 ]:

[2 ] Inte re sti ng l y , i t i s v al i d C be cau se C h as a co nce pt o f t e nt a t i v e de f i ni t i on , w h i ch i s a v ari abl e de f i ni ti o n w i th o u t an i ni ti al i z e r and can appe ar m o re th an o nce i n a pro g ram .

// Translation unit 1: int counter; // Translation unit 2: int counter; // ERROR: defined twice! (ODR violation)

T h i s ru l e do e s no t appl y to e nti ti e s w i th i nt e r na l l i nk a g e (e sse nti al l y , e nti ti e s de cl are d i n an u nnam e d nam e space sco pe o r i n th e g l o bal sco pe u si ng th e static spe ci f i e r) be cau se e v e n w h e n tw o su ch e nti ti e s h av e th e sam e nam e , th e y are co nsi de re d di sti nct. In th e sam e v e i n, e nti ti e s de cl are d i n u nnam e d nam e space s are co nsi de re d di sti nct i f th e y appe ar i n di sti nct transl ati o n u ni ts. F o r e x am pl e , th e f o l l o w i ng tw o transl ati o n u ni ts can be co m bi ne d i nto a v al i d C + + pro g ram :

// Translation unit 1: static counter = 2; // unrelated to other translation units namespace {

Page 530: CPlusPlus Templates The Complete Guide

void unique() // unrelated to other translation units { } } // Translation unit 2: static counter = 0; // unrelated to other translation units namespace { void unique() // unrelated to other translation units { ++counter; } } int main() { unique(); }

F u rth e rm o re , th e re m u st be e x a c t l y one o f th e pre v i o u sl y m e nti o ne d i te m s i n th e pro g ram i f th e y are us e d. T h e te rm us e d i n th i s co nte x t h as a pre ci se m e ani ng . It i ndi cate s th at th e re i s so m e so rt o f re f e re nce to th e e nti ty so m e w h e re i n th e pro g ram . T h i s re f e re nce can be an acce ss to th e v al u e o f a v ari abl e , a cal l to a f u ncti o n, o r th e addre ss o f su ch an e nti ty . T h i s re f e re nce can be e x pl i ci t i n th e so u rce , o r i t can be i m pl i ci t. F o r e x am pl e , a new e x pre ssi o n m ay cre ate an i m pl i ci t cal l to th e asso ci ate d delete o pe rato r to h andl e si tu ati o ns w h e n a co nstru cto r th ro w s an e x ce pti o n re q u i ri ng th e u nu se d (bu t al l o cate d) m e m o ry to be cl e ane d u p. A no th e r e x am pl e co nsi sts o f co py co nstru cto rs, w h i ch m u st be de f i ne d e v e n i f th e y e nd u p be i ng o pti m i z e d aw ay . V i rtu al f u ncti o ns are al so i m pl i ci tl y u se d (by th e i nte rnal stru ctu re s th at e nabl e v i rtu al f u ncti o n cal l s), u nl e ss th e y are pu re v i rtu al f u ncti o ns. S e v e ral o th e r k i nds o f i m pl i ci t u se s e x i st, bu t w e o m i t th e m f o r th e sak e o f co nci se ne ss.

T h e re are tw o k i nds o f re f e re nce s th at do not co nsti tu te a u se i n th e pre v i o u s se nse : T h e f i rst k i nd o ccu rs w h e n a re f e re nce to an e nti ty appe ars as part o f a sizeof o pe rato r. T h e se co nd k i nd i s si m i l ar bu t w i th a tw i st: If a re f e re nce appe ars as part o f a typeid o pe rato r (se e S e cti o n 5 .6 o n pag e 5 8 ), i t i s no t a u se i n th e pre v i o u s se nse , u nl e ss th e arg u m e nt o f th e typeid o pe rato r e nds de si g nati ng a po l y m o rph i c o bj e ct (an o bj e ct w i th (po ssi bl y i nh e ri te d) v i rtu al f u ncti o ns). F o r e x am pl e , co nsi de r th e f o l l o w i ng si ng l e -f i l e pro g ram :

#include <typeinfo> class Decider { #if defined(DYNAMIC) virtual ~Decider() { } #endif };

Page 531: CPlusPlus Templates The Complete Guide

extern Decider d; int main() { const char* name = typeid(d).name(); return (int)sizeof(d); }

T h i s i s a v al i d pro g ram i f and o nl y i f th e pre pro ce sso r sy m bo l DYNAMIC i s no t de f i ne d. Inde e d, th e v ari abl e d i s no t de f i ne d, bu t th e re f e re nce to d i n sizeof(d) do e s no t co nsti tu te a u se , and th e re f e re nce i n typeid(d) i s a u se o nl y i f d i s an o bj e ct o f a po l y m o rph i c ty pe (be cau se i n g e ne ral i t i s no t al w ay s po ssi bl e to de te rm i ne th e re su l t o f a po l y m o rph i c typeid o pe rati o n u nti l ru n ti m e ).

A cco rdi ng to th e C + + standard, th e co nstrai nts de scri be d i n th i s se cti o n do no t re q u i re a di ag no sti c f ro m a C + + i m pl e m e ntati o n. In practi ce , th e y are al m o st al w ay s re po rte d by l i nk e rs as du pl i cate o r m i ssi ng de f i ni ti o ns.

A.3.2 One-per-Translation Unit Constraints

No e nti ty can be de f i ne d m o re th an o nce i n a transl ati o n u ni t. S o th e f o l l o w i ng e x am pl e i s i nv al i d

C + + :

inline void f() {} inline void f() {} // ERROR: duplicate definition

T h i s i s o ne o f th e m ai n re aso ns f o r su rro u ndi ng th e co de i n h e ade r f i l e s w i th so -cal l e d g ua r ds :

// File guard_demo.hpp: #ifndef GUARD_DEMO_HPP #define GUARD_DEMO_HPP … #endif // GUARD_DEMO_HPP

S u ch g u ards e nsu re th at th e se co nd ti m e a h e ade r f i l e i s #included, i ts co nte nts are di scarde d, th e re by av o i di ng a du pl i cate de f i ni ti o n o f any cl ass, i nl i ne f u ncti o n, o r te m pl ate i t co ntai ns.

T h e O D R al so spe ci f i e s th at ce rtai n e nti ti e s m us t be de f i ne d i n ce rtai n ci rcu m stance s. T h i s can be th e case f o r cl ass ty pe s, i nl i ne f u ncti o ns, and no n-export te m pl ate s. In th e f o l l o w i ng f e w parag raph s w e re v i e w th e de tai l e d ru l e s.

Page 532: CPlusPlus Templates The Complete Guide

A cl ass ty pe X (i ncl u di ng structs and unions) m us t be de f i ne d i n a transl ati o n u ni t p r i or to any o f th e f o l l o w i ng k i nds o f u se s i n th at transl ati o n u ni t:

• T h e cre ati o n o f an o bj e ct o f ty pe X (f o r e x am pl e , as a v ari abl e de cl arati o n o r th ro u g h a new e x pre ssi o n). T h e cre ati o n co u l d be i ndi re ct, f o r e x am pl e , w h e n an o bj e ct th at i tse l f co ntai ns an o bj e ct o f ty pe X i s be i ng cre ate d.

• T h e de cl arati o n o f a data m e m be r o f ty pe X. • A ppl y i ng th e sizeof o r typeid o pe rato r to an o bj e ct o f ty pe X. • E x pl i ci tl y o r i m pl i ci tl y acce ssi ng m e m b e rs o f ty pe X. • C o nv e rti ng an e x pre ssi o n to o r f ro m ty pe X u si ng any k i nd o f co nv e rsi o n,

o r co nv e rti ng an e x pre ssi o n to o r f ro m a po i nte r o r re f e re nce to X (e x ce pt void*) u si ng an i m pl i ci t cast, static_cast, o r dynamic_cast.

• A ssi g ni ng a v al u e to an o bj e ct o f ty pe X. • D e f i ni ng o r cal l i ng a f u ncti o n w i th an arg u m e nt o r re tu rn ty pe o f ty pe X.

J u st de cl ari ng su ch a f u ncti o n do e sn' t ne e d th e ty pe to be de f i ne d h o w e v e r.

T h e ru l e s f o r ty pe s al so appl y to ty pe s X g e ne rate d f ro m cl ass te m pl ate s, w h i ch m e ans th at th e co rre spo ndi ng te m pl ate s m u st be de f i ne d i n th o se si tu ati o ns i n w h i ch su ch a ty pe X m u st be de f i ne d. T h e se si tu ati o ns cre ate so -cal l e d p oi nt s of i ns t a nt i a t i on o r P O I s (se e S e cti o n 1 0 .3 .2 o n pag e 1 4 6 ).

Inl i ne f u ncti o ns m u st be de f i ne d i n e v e ry transl ati o n u ni t i n w h i ch th e y are u se d (i n w h i ch th e y are cal l e d o r th e i r addre ss i s tak e n). H o w e v e r, u nl i k e cl ass ty pe s, th e i r de f i ni ti o n can f o l l o w th e po i nt o f u se :

inline int not_so_fast(); int main() { not_so_fast(); } inline int not_so_fast() { }

A l th o u g h th i s i s v al i d C + + , so m e co m pi l e rs do no t actu al l y " i nl i ne " th e cal l to a f u ncti o n w i th a bo dy th at h as no t be e n se e n y e t; h e nce th e de si re d e f f e ct m ay no t be ach i e v e d.

J u st as w i th cl ass te m pl ate s, th e u se o f a f u ncti o n g e ne rate d f ro m a param e te ri z e d f u ncti o n de cl arati o n (a f u ncti o n o r m e m be r f u ncti o n te m pl ate , o r a m e m be r f u ncti o n o f a cl ass te m pl ate ) cre ate s a po i nt o f i nstanti ati o n. U nl i k e cl ass te m pl ate s, h o w e v e r, th e co rre spo ndi ng de f i ni ti o n can appe ar af te r th e po i nt o f

Page 533: CPlusPlus Templates The Complete Guide

i nstanti ati o n (o r no t at al l i f i t i s e x po rte d).

T h e f ace ts o f th e O D R e x pl ai ne d i n th i s appe ndi x are g e ne ral l y e asi l y v e ri f i e d by C + + co m pi l e rs; h e nce th e C + + standard re q u i re s th at co m pi l e rs i ssu e so m e so rt o f di ag no sti c w h e n o ne o f th e se ru l e s i s v i o l ate d. A n e x ce pti o n i s th e l ack o f de f i ni ti o n o f a no ne x po rte d param e te ri z e d f u ncti o n. S u ch si tu ati o ns are ty pi cal l y no t di ag no se d.

A.3.3 Cross-Translation Unit Equivalence Constraints

T h e abi l i ty to de f i ne ce rtai n k i nds o f e nti ti e s i n m o re th an o ne transl ati o n u ni t bri ng s w i th i t th e po te nti al f o r a ne w k i nd o f e rro r: m u l ti pl e de f i ni ti o ns th at do n' t m atch . U nf o rtu nate l y , su ch e rro rs are h ard to de te ct by tradi ti o nal co m pi l e r te ch no l o g y i n w h i ch transl ati o n u ni ts are pro ce sse d o ne at a ti m e . C o nse q u e ntl y , th e C + + standard do e sn' t m a nda t e th at di f f e re nce s i n m u l ti pl e de f i ni ti o ns be de te cte d o r di ag no se d (i t do e s a l l ow i t, o f co u rse ). If th i s cro ss-transl ati o n u ni t co nstrai nt i s v i o l ate d, h o w e v e r, th e C + + standard q u al i f i e s th i s as l e adi ng to unde f i ne d b e h a v i or , w h i ch m e ans th at any th i ng re aso nabl e o r u nre aso nabl e m ay h appe n. T y pi cal l y , su ch u ndi ag no se d e rro rs m ay l e ad to pro g ram crash e s o r w ro ng re su l ts, bu t i n pri nci pl e th e y can al so l e ad to o th e r, m o re di re ct, k i nds o f dam ag e (f o r e x am pl e , f i l e co rru pti o n). [3 ]

[3 ] V e rsi o n 1 o f th e g cc co m pi l e r actu al l y j o k i ng l y di d th i s by starti ng th e g am e o f R o g u e i n si tu ati o ns l i k e th i s.

T h e cro ss-transl ati o n u ni t co nstrai nts spe ci f y th at w h e n an e nti ty i s de f i ne d i n tw o di f f e re nt pl ace s, th e tw o pl ace s m u st co nsi st o f e x actl y th e sam e se q u e nce o f to k e ns (th e k e y w o rds, o pe rato rs, i de nti f i e rs, and so f o rth re m ai ni ng af te r pre pro ce ssi ng ). F u rth e rm o re , th e se to k e ns m u st m e an th e sam e th i ng i n th e i r re spe cti v e co nte x t (f o r e x am pl e , th e i de nti f i e rs m ay ne e d to re f e r to th e sam e v ari abl e ).

C o nsi de r th e f o l l o w i ng e x am pl e :

// Translation unit 1: static int counter = 0; inline void increase_counter() { ++counter; } int main() { } // Translation unit 2: static int counter = 0; inline void increase_counter() {

Page 534: CPlusPlus Templates The Complete Guide

++counter; }

T h i s e x am pl e i s i n e rro r be cau se e v e n th o u g h th e to k e n se q u e nce f o r th e i nl i ne f u ncti o n increase_counter() l o o k s i de nti cal i n bo th transl ati o n u ni ts, th e y co ntai n a to k e n counter th at re f e rs to tw o di f f e re nt e nti ti e s. Inde e d, be cau se th e tw o v ari abl e s nam e d counter h av e i nte rnal l i nk ag e (static spe ci f i e r), th e y are u nre l ate d de spi te h av i ng th e sam e nam e . No te th at th i s i s an e rro r e v e n th o u g h ne i th e r o f th e i nl i ne f u ncti o ns i s actu al l y u se d.

P l aci ng th e de f i ni ti o ns o f e nti ti e s th at can be de f i ne d i n m u l ti pl e transl ati o n u ni ts i n h e ade r f i l e s th at are #included w h e ne v e r th e de f i ni ti o ns are ne e de d e nsu re s th at to k e n se q u e nce s are i de nti cal i n al m o st al l si tu ati o ns. [4 ] W i th th i s appro ach , si tu ati o ns i n w h i ch tw o i de nti cal to k e ns re f e r to di f f e re nt th i ng s be co m e f ai rl y rare , bu t w h e n i t do e s h appe n, th e re su l ti ng e rro rs are o f te n m y ste ri o u s and h ard to track .

[4 ] O ccasi o nal l y , co ndi ti o nal co m pi l ati o n di re cti v e s e v al u ate di f f e re ntl y i n di f f e re nt transl ati o n u ni ts. U se su ch di re cti v e s w i th care . O th e r di f f e re nce s are po ssi bl e to o , bu t th e y are e v e n l e ss co m m o n.

T h e cro ss-transl ati o n u ni t co nstrai nts appl y no t o nl y to e nti ti e s th at can be de f i ne d i n m u l ti pl e pl ace s, bu t al so to de f au l t arg u m e nts i n de cl arati o ns. In o th e r w o rds, th e f o l l o w i ng pro g ram h as u nde f i ne d be h av i o r:

// Translation unit 1: void unused(int = 3); int main() { } // Translation unit 2: void unused(int = 4);

W e sh o u l d no te h e re th at th e e q u i v al e nce o f to k e n stre am s can so m e ti m e s i nv o l v e su btl e i m pl i ci t e f f e cts. T h e f o l l o w i ng e x am pl e i s l i f te d (i n a sl i g h tl y m o di f i e d f o rm ) f ro m th e C + + standard:

// Translation unit 1: class X { public: X(int); X(int, int); }; X::X(int = 0) { }

Page 535: CPlusPlus Templates The Complete Guide

class D : public X { }; D d2; // X(int) called by D() // Translation unit 2: class X { public: X(int); X(int, int); }; X::X(int = 0, int = 0) { } class D : public X { // X(int, int) called by D(); }; // D()'s implicit definition violates the ODR

In th i s e x am pl e , th e pro bl e m o ccu rs be cau se th e i m pl i ci tl y g e ne rate d de f au l t co nstru cto r o f cl ass D i s di f f e re nt i n th e tw o transl ati o n u ni ts. O ne cal l s th e X co nstru cto r tak i ng o ne arg u m e nt, and th e o th e r cal l s th e X co nstru cto r tak i ng tw o arg u m e nts. If any th i ng , th i s e x am pl e i s an addi ti o nal i nce nti v e to l i m i t de f au l t arg u m e nts to o ne l o cati o n i n th e pro g ram (i f po ssi bl e , th i s l o cati o n sh o u l d be i n a h e ade r f i l e ). F o rtu nate l y , pl aci ng de f au l t arg u m e nts o n o u t-o f -cl ass de f i ni ti o ns i s a rare practi ce .

T h e re i s al so an e x ce pti o n to th e ru l e th at say s th at i de nti cal to k e ns m u st re f e r to i de nti cal e nti ti e s. If i de nti cal to k e ns re f e r to u nre l ate d co nstants th at h av e th e sam e v al u e and th e addre ss o f th e re su l ti ng e x pre ssi o ns i s no t u se d, th e n th e to k e ns are co nsi de re d e q u i v al e nt. T h i s e x ce pti o n al l o w s f o r pro g ram stru ctu re s l i k e th e f o l l o w i ng :

// File header.hpp: #ifndef HEADER_HPP #define HEADER_HPP int const length = 10; class MiniBuffer { char buf[length]; ... }; #endif // HEADER_HPP

In pri nci pl e , w h e n th i s h e ade r f i l e i s i ncl u de d i n tw o di f f e re nt transl ati o n u ni ts, tw o di sti nct co nstant v ari abl e s nam e d length are cre ate d be cau se const i n th i s co nte x t i m pl i e s static. H o w e v e r, su ch co nstant v ari abl e s are o f te n m e ant to de f i ne co m pi l e -ti m e co nstant v al u e s, no t a parti cu l ar sto rag e l o cati o n at ru n ti m e . H e nce , i f w e do n' t f o rce su ch a sto rag e l o cati o n to e x i st (by re f e rri ng to th e

Page 536: CPlusPlus Templates The Complete Guide

addre ss o f th e v ari abl e ), i t i s su f f i ci e nt f o r th e tw o co nstants to h av e th e sam e v al u e . T h i s e x ce pti o n to th e O D R e q u i v al e nce ru l e s appl i e s o nl y to i nte g ral and e nu m e rati o n v al u e s (f l o ati ng -po i nt ty pe s and po i nte r ty pe s do n' t f al l i n th i s cate g o ry ).

F i nal l y , a no te abo u t te m pl ate s. T h e nam e s i n te m pl ate s bi nd i n tw o ph ase s. S o -cal l e d nonde p e nde nt na m e s bi nd at th e po i nt w h e re th e te m pl ate i s de f i ne d. F o r th e se , th e e q u i v al e nce ru l e s are h andl e d si m i l arl y to o th e r no nte m pl ate de f i ni ti o ns. F o r nam e s th at bi nd at th e po i nt o f i nstanti ati o n, th e e q u i v al e nce ru l e s m u st be appl i e d at th at po i nt, and th e bi ndi ng s m u st be e q u i v al e nt. T h i s l e ads to a su btl e o bse rv ati o n: A l th o u g h export e d te m pl ate s are de f i ne d i n o nl y o ne l o cati o n, th e y m ay h av e m u l ti pl e i nstance s w h i ch m u st o be y th e e q u i v al e nce ru l e s. H e re i s a parti cu l arl y f ar-f e tch e d v i o l ati o n o f th e O D R :

// File header.hpp: #ifndef HEADER_HPP #define HEADER_HPP enum Color { red, green, blue }; // the associated namespace of Color is the global namespace export template<typename T> void highlight(T); void init(); #endif // HEADER_HPP // File tmpl_def.cpp: #include "header.hpp" export template<typename T> void highlight(T x) { paint(x); // (1) a dependent call: argument-dependent lookup required } // File init.cpp: #include "header.hpp" namespace { // unnamed namespace! void paint(Color c) // (2) { … } } void init() { highlight(blue); // argument-dependent lookup of (1) resolves to (2) } // File main.cpp: #include "header.hpp"

Page 537: CPlusPlus Templates The Complete Guide

namespace { // unnamed namespace! void paint(Color c) // (3) { … } } int main() { init(); highlight(red); // argument-dependent lookup of (1) resolves to (3) }

T o u nde rstand th i s e x am pl e , w e m u st re m e m be r th at f u ncti o ns de f i ne d i n an u nnam e d nam e space h av e e x te rnal l i nk ag e , bu t th e y are di sti nct f ro m any f u ncti o ns de f i ne d i n an u nnam e d nam e space o f o th e r transl ati o n u ni ts. T h e re f o re , th e tw o paint() f u ncti o ns are di sti nct. H o w e v e r, th e cal l to paint() i n th e e x po rte d te m pl ate h as a te m pl ate -de pe nde nt arg u m e nt and i s th e re f o re no t bo u nd u nti l th e po i nts o f i nstanti ati o n. In o u r e x am pl e , th e re are tw o po i nts o f i nstanti ati o n f o r highlight<Color> , bu t th e y re su l t i n di f f e re nt bi ndi ng s o f th e nam e paint; h e nce th e pro g ram i s i nv al i d.

Page 538: CPlusPlus Templates The Complete Guide

Appendix B. Overload Resolution

O v e r l oa d r e s ol ut i on i s th e pro ce ss th at se l e cts th e f u ncti o n to cal l f o r a g i v e n cal l e x pre ssi o n. C o nsi de r th e f o l l o w i ng si m pl e e x am pl e :

void display_num(int); // (1) void display_num(double); // (2) int main() { display_num(399); // matches (1) better than (2) display_num(3.99); // matches (2) better than (1) }

In th i s e x am pl e , th e f u ncti o n nam e display_num() i s sai d to be ov e r l oa de d. W h e n th i s nam e i s u se d i n a cal l , a C + + co m pi l e r m u st th e re f o re di sti ng u i sh be tw e e n th e v ari o u s candi date s u si ng addi ti o nal i nf o rm ati o n; m o stl y , th i s i nf o rm ati o n i s th e ty pe s o f th e cal l arg u m e nts. In o u r e x am pl e i t m ak e s i ntu i ti v e se nse to cal l th e int v e rsi o n w h e n th e f u ncti o n i s cal l e d w i th an i nte g e r arg u m e nt and th e double v e rsi o n w h e n a f l o ati ng -po i nt arg u m e nt i s pro v i de d. T h e f o rm al pro ce ss th at atte m pts to m o de l th i s i ntu i ti v e ch o i ce i s th e o v e rl o ad re so l u ti o n pro ce ss.

T h e g e ne ral i de as be h i nd th e ru l e s th at g u i de o v e rl o ad re so l u ti o n are si m pl e e no u g h , bu t th e de tai l s h av e be co m e q u i te co m pl e x du ri ng th e C + + standardi z ati o n pro ce ss. T h i s co m pl e x i ty w as dri v e n m o stl y by th e de si re to su ppo rt v ari o u s re al -w o rl d e x am pl e s th at i ntu i ti v e l y (to a h u m an) se e m to h av e an " o bv i o u sl y be st m atch , " bu t w h e n try i ng to f o rm al i z e th i s i ntu i ti o n, v ari o u s su btl e ti e s aro se .

In th i s appe ndi x w e pro v i de a re aso nabl y de tai l e d su rv e y o f th e o v e rl o ad re so l u ti o n ru l e s. H o w e v e r, th e co m pl e x i ty o f th i s pro ce ss i s su ch th at w e do no t cl ai m to co v e r e v e ry part o f th e to pi c.

Page 539: CPlusPlus Templates The Complete Guide

B.1 When Does Overload Resolution Kick In?

O v e rl o ad re so l u ti o n i s j u st o ne part o f th e co m pl e te pro ce ssi ng o f a f u ncti o n cal l . In f act, i t i s no t part o f e v e ry f u ncti o n cal l . F i rst, cal l s th ro u g h f u ncti o n po i nte rs and cal l s th ro u g h po i nte rs to m e m be r f u ncti o ns are no t su bj e ct to o v e rl o ad re so l u ti o n be cau se th e f u ncti o n to cal l i s e nti re l y de te rm i ne d (at ru n ti m e ) by th e po i nte rs. S e co nd, f u ncti o n-l i k e m acro s canno t be o v e rl o ade d and are th e re f o re no t su bj e ct to o v e rl o ad re so l u ti o n.

A t a v e ry h i g h l e v e l , a cal l to a nam e d f u ncti o n can be pro ce sse d i n th e f o l l o w i ng w ay :

• T h e nam e i s l o o k e d u p to f o rm an i ni ti al ov e r l oa d s e t . • If ne ce ssary , th i s se t i s tw e ak e d i n v ari o u s w ay s (f o r e x am pl e , te m pl ate

de du cti o n o ccu rs). • A ny candi date th at do e sn' t m atch th e cal l at al l (e v e n af te r co nsi de ri ng

i m pl i ci t co nv e rsi o ns and de f au l t arg u m e nts) i s e l i m i nate d f ro m th e o v e rl o ad se t. T h i s re su l ts i n a se t o f so -cal l e d v i a b l e f unc t i on c a ndi da t e s .

• O v e rl o ad re so l u ti o n i s pe rf o rm e d to f i nd a b e s t candi date . If th e re i s o ne , i t i s se l e cte d; o th e rw i se , th e cal l i s am bi g u o u s.

• T h e se l e cte d candi date i s ch e ck e d. F o r e x am pl e , i f i t i s an i nacce ssi bl e pri v ate m e m be r, a di ag no sti c i s i ssu e d.

E ach o f th e se ste ps h as i ts o w n su btl e ti e s, bu t o v e rl o ad re so l u ti o n i s arg u abl y th e m o st co m pl e x . F o rtu nate l y , a f e w si m pl e pri nci pl e s cl ari f y th e m aj o ri ty o f si tu ati o ns. W e e x am i ne th e se pri nci pl e s ne x t.

Page 540: CPlusPlus Templates The Complete Guide

B.2 Simplified Overload Resolution

O v e rl o ad re so l u ti o n rank s th e v i abl e candi date f u ncti o ns by co m pari ng h o w e ach arg u m e nt o f th e cal l m atch e s th e co rre spo ndi ng param e te r o f th e candi date s. F o r o ne candi date to be co nsi de re d be tte r th an ano th e r, th e be tte r candi date canno t h av e any o f i ts param e te rs be a w o rse m atch th an th e co rre spo ndi ng param e te r i n th e o th e r candi date . T h e f o l l o w i ng e x am pl e i l l u strate s th i s:

void combine(int, double); void combine(long, int); int main() { combine (1, 2); // ambiguous! }

In th i s e x am pl e , th e cal l to combine() i s am bi g u o u s be cau se th e f i rst candi date m atch e s th e f i rst arg u m e nt (th e l i te ral 1 o f ty pe int) b e s t , w h e re as th e se co nd candi date m atch e s th e se co nd arg u m e nt b e s t . W e co u l d arg u e th at int i s i n so m e se nse cl o se r to long th an to double (w h i ch su ppo rts ch o o si ng th e se co nd candi date ), bu t C + + do e s no t atte m pt to de f i ne a m e asu re o f cl o se ne ss th at i nv o l v e s m u l ti pl e cal l arg u m e nts.

G i v e n th i s f i rst pri nci pl e , w e are l e f t w i th spe ci f y i ng h o w w e l l a g i v e n arg u m e nt m atch e s th e co rre spo ndi ng param e te r o f a v i abl e candi date . A s a f i rst appro x i m ati o n w e can rank th e po ssi bl e m atch e s as f o l l o w s (f ro m be st to w o rst):

• P e rf e ct m atch . T h e param e te r h as th e ty pe o f th e e x pre ssi o n, o r i t h as a ty pe th at i s a re f e re nce to th e ty pe o f th e e x pre ssi o n (po ssi bl y w i th adde d const and/o r volatile q u al i f i e rs).

• M atch w i th m i no r adj u stm e nts. T h i s i ncl u de s, f o r e x am pl e , th e de cay o f an array v ari abl e to a po i nte r to i ts f i rst e l e m e nt, o r th e addi ti o n o f const to m atch an arg u m e nt o f ty pe int** to a param e te r o f ty pe int const* const*.

• M atch w i th pro m o ti o n. P ro m o ti o n i s a k i nd o f i m pl i ci t co nv e rsi o n th at i ncl u de s th e co nv e rsi o n o f sm al l i nte g ral ty pe s (su ch as bool , char, short , and so m e ti m e s e nu m e rati o ns) to int, unsigned int , long o r unsigned long , and th e co nv e rsi o n o f float to double.

• M atch w i th standard co nv e rsi o ns o nl y . T h i s i ncl u de s any so rt o f standard co nv e rsi o n (su ch as int to float) bu t e x cl u de s th e i m pl i ci t cal l to a co nv e rsi o n o pe rato r o r a co nv e rti ng co nstru cto r.

• M atch w i th u se r-de f i ne d co nv e rsi o ns. T h i s al l o w s any k i nd o f i m pl i ci t

Page 541: CPlusPlus Templates The Complete Guide

co nv e rsi o n. • M atch w i th e l l i psi s. A n e l l i psi s param e te r can m atch al m o st any ty pe (bu t

no n-P O D cl ass ty pe s re su l t i n u nde f i ne d be h av i o r).

T h e f o l l o w i ng co ntri v e d e x am pl e i l l u strate s so m e o f th e se m atch e s:

int f1(int); // (1) int f1(double); // (2) f1(4); // calls (1): perfect match // ((2) requires a standard conversion) int f2(int); // (3) int f2(char); // (4) f2(true); // calls (3): match with promotion // ((4) requires stronger standard conversion) class X { public: X(int); }; int f3(X); // (5) int f3(...); // (6) f3(7); // calls (5): match with user-defined conversion // ((6) requires a match with ellipsis)

No te th at o v e rl o ad re so l u ti o n o ccu rs a f t e r te m pl ate arg u m e nt de du cti o n, and th i s de du cti o n do e s no t co nsi de r al l th e se so rts o f co nv e rsi o ns. T h e f o l l o w i ng e x am pl e i l l u strate s th i s:

template <typename T> class MyString { public: MyString(T const*); // converting constructor ... }; template<typename T> MyString<T> truncate(MyString<T> const&, int); int main() { MyString<char> str1, str2; str1 = truncate<char>("Hello World", 5); // OK str2 = truncate("Hello World", 5); // ERROR }

T h e i m pl i ci t co nv e rsi o n pro v i de d th ro u g h th e co nv e rti ng co nstru cto r i s no t co nsi de re d du ri ng te m pl ate arg u m e nt de du cti o n. T h e i ni ti al i z ati o n o f str2 f i nds no v i abl e f u ncti o n truncate(); h e nce o v e rl o ad re so l u ti o n i s no t pe rf o rm e d at al l .

T h e pre v i o u s pri nci pl e s are o nl y a f i rst appro x i m ati o n, bu t th e y co v e r m any case s.

Page 542: CPlusPlus Templates The Complete Guide

Y e t th e re are q u i te a f e w co m m o n si tu ati o ns th at are no t ade q u ate l y e x pl ai ne d by th e se ru l e s. W e pro ce e d w i th a bri e f di scu ssi o n o f th e m o st i m po rtant re f i ne m e nts o f th e se ru l e s.

B.2.1 The Implied Argument for Member Functions

C al l s to no nstati c m e m b e r f u ncti o ns h av e a h i dde n param e te r th at i s acce ssi bl e i n th e de f i ni ti o n o f th e m e m be r f u ncti o n as *this. F o r a m e m be r f u ncti o n o f a cl ass MyClass, th e h i dde n param e te r i s u su al l y o f ty pe MyClass& (f o r no n-const m e m be r f u ncti o ns) o r MyClass const& (f o r const m e m be r f u ncti o ns). [1] T h i s i s so m e w h at su rpri si ng g i v e n th at this h as a po i nte r ty pe . It w o u l d h av e be e n ni ce r to m ak e this e q u i v al e nt to w h at i s no w *this. H o w e v e r, this w as part o f an e arl y v e rsi o n o f C + + be f o re re f e re nce ty pe s w e re part o f th e l ang u ag e , and by th e ti m e re f e re nce ty pe s w e re adde d, to o m u ch co de al re ady de pe nde d o n this be i ng a po i nte r.

[1] It co u l d al so be o f ty pe MyClass volatile& o r MyClass const volatile& i f th e m e m be r f u ncti o n w as volatile , bu t th i s i s e x tre m e l y rare .

T h e h i dde n *this param e te r parti ci pate s i n o v e rl o ad re so l u ti o n j u st l i k e th e e x pl i ci t param e te rs. M o st o f th e ti m e th i s i s q u i te natu ral , bu t o ccasi o nal l y i t co m e s u ne x pe cte dl y . T h e f o l l o w i ng e x am pl e sh o w s a stri ng -l i k e cl ass th at do e s no t w o rk as i nte nde d (y e t w e h av e se e n su ch co de i n th e re al w o rl d):

#include <stddef.h> class BadString { public: BadString(char const*); ... // character access through subscripting: char& operator[] (size_t); // (1) char const& operator[] (size_t) const; // implicit conversion to null-terminated byte string: operator char* (); // (2) operator char const* (); ... }; int main() { BadString str("correkt"); str[5] = 'c'; // possibly an overload resolution ambiguity! }

Page 543: CPlusPlus Templates The Complete Guide

A t f i rst, no th i ng se e m s am bi g u o u s abo u t th e e x pre ssi o n str[5]. T h e su bscri pt o pe rato r at (1 ) se e m s l i k e a pe rf e ct m atch . H o w e v e r, i t i s no t q ui t e pe rf e ct be cau se th e arg u m e nt 5 h as ty pe int , and th e o pe rato r e x pe cts an u nsi g ne d i nte g e r ty pe (size_t and std::size_t u su al l y h av e ty pe unsigned int o r unsigned long , bu t ne v e r ty pe int). S ti l l , a si m pl e standard i nte g e r co nv e rsi o n m ak e s (1 ) e asi l y v i abl e . H o w e v e r, th e re i s ano th e r v i abl e candi date : th e bu i l t-i n su bscri pt o pe rato r. Inde e d, i f w e appl y th e i m pl i ci t co nv e rsi o n o pe rato r to str (w h i ch i s th e i m pl i ci t m e m be r f u ncti o n arg u m e nt), w e o btai n a po i nte r ty pe , and no w th e bu i l t-i n su bscri pt o pe rato r appl i e s. T h i s bu i l t-i n o pe rato r tak e s an arg u m e nt o f ty pe ptrdiff_t , w h i ch o n m any pl atf o rm s i s e q u i v al e nt to int and th e re f o re i s a pe rf e ct m atch f o r th e arg u m e nt 5. S o e v e n th o u g h th e bu i l t-i n su bscri pt o pe rato r i s a po o r m atch (by u se r-de f i ne d co nv e rsi o n) f o r th e i m pl i e d arg u m e nt, i t i s a be tte r m atch th an th e o pe rato r de f i ne d at (1 ) f o r th e actu al su bscri pt! H e nce th e po te nti al am bi g u i ty . [2 ] T o so l v e th i s k i nd o f pro bl e m po rtabl y , y o u can de cl are o pe rato r [] w i th a ptrdiff_t param e te r, o r y o u can re pl ace th e i m pl i ci t ty pe co nv e rsi o n to char* by an e x pl i ci t co nv e rsi o n (w h i ch i s u su al l y re co m m e nde d any w ay ).

[2 ] No te th at th e am bi g u i ty e x i sts o nl y o n pl atf o rm s f o r w h i ch size_t i s a sy no ny m f o r unsigned int.O n pl atf o rm s f o r w h i ch i t i s a sy no ny m f o r unsigned long , th e ty pe ptrdiff_t i s a ty pe de f o f long , and no am bi g u i ty e x i sts be cau se th e bu i l t-i n su bscri pt o pe rato r al so re q u i re s a co nv e rsi o n o f th e su bscri pt e x pre ssi o n.

It i s po ssi bl e f o r a se t o f v i abl e candi date s to co ntai n bo th stati c and no nstati c m e m be rs. W h e n co m pari ng a stati c m e m be r w i th a no nstati c m e m be r, th e q u al i ty o f th e m atch o f th e i m pl i ci t arg u m e nt i s i g no re d (o nl y th e no nstati c m e m be r h as an i m pl i ci t *this arg u m e nt).

B.2.2 Refining the Perfect Match

F o r an arg u m e nt o f ty pe int , th e re are th re e co m m o n param e te r ty pe s th at co nsti tu te a pe rf e ct m atch : int, int& , and int const&. H o w e v e r, i t i s rath e r co m m o n to o v e rl o ad a f u ncti o n o n bo th k i nds o f re f e re nce s:

void report(int&); // (1) void report(int const&); // (2) int main() { for (int k = 0; k<10; ++k) { report(k); // calls (1) } report(42); // calls (2) }

Page 544: CPlusPlus Templates The Complete Guide

In su ch case s th e v e rsi o n w i th o u t th e e x tra const i s pre f e rre d f o r l v al u e s, w h e re as th e v e rsi o n w i th const i s pre f e rre d f o r rv al u e s.

No te th at th i s al so appl i e s to th e i m pl i ci t arg u m e nt o f a m e m b e r f u ncti o n cal l :

class Wonder { public: void tick(); // (1) void tick() const; // (2) void tack() const; // (3) }; void run(Wonder& device) { device.tick(); // calls (1) device.tack(); // calls (3) because there is no non-const version // of Wonder::tack() }

F i nal l y , th e f o l l o w i ng m o di f i cati o n o f o u r e arl i e r e x am pl e i l l u strate s th at tw o pe rf e ct m atch e s can al so cre ate an am bi g u i ty i f y o u o v e rl o ad w i th and w i th o u t re f e re nce s:

void report(int); // (1) void report(int&); // (2) void report(int const&); // (3) int main() { for (int k = 0; k<10; ++k) { report(k); // ambiguous: (1) and (2) match equally well } report(42); // ambiguous: (1) and (3) match equally well }

T o su m m ari z e :

• T and T const& bo th m atch e q u al l y w e l l f o r an rv al u e o f ty pe T. • T and T& bo th m atch e q u al l y w e l l f o r an l v al u e o f ty pe T.

Page 545: CPlusPlus Templates The Complete Guide

B.3 Overloading Details

T h e pre v i o u s se cti o n co v e rs m o st o f th e o v e rl o adi ng si tu ati o ns e nco u nte re d i n e v e ry day C + + pro g ram m i ng . T h e re are , u nf o rtu nate l y , m any m o re ru l e s and e x ce pti o ns to th e se ru l e s—m o re th an i s re aso nabl e to pre se nt i n a bo o k th at i s no t re al l y abo u t f u ncti o n o v e rl o adi ng i n C + + . No ne th e l e ss, w e di scu ss so m e o f th e m h e re i n part be cau se th e y appl y so m e w h at m o re o f te n th an o th e r ru l e s and i n part to pro v i de a se nse f o r h o w de e p th e de tai l s g o .

B.3.1 Prefer Nontemplates

W h e n al l o th e r aspe cts o f o v e rl o ad re so l u ti o n are e q u al , a no nte m pl ate f u ncti o n i s pre f e rre d o v e r an i nstance o f a te m pl ate (i t do e sn' t m atte r w h e th e r th at i nstance i s g e ne rate d f ro m th e g e ne ri c te m pl ate de f i ni ti o n o r w h e th e r i t i s pro v i de d as an e x pl i ci t spe ci al i z ati o n). F o r e x am pl e :

template<typename T> int f(T); // (1) void f(int); // (2) int main() { return f(7); // ERROR: selects (2), which doesn't return a value }

T h i s e x am pl e al so cl e arl y i l l u strate s th at o v e rl o ad re so l u ti o n no rm al l y do e s no t i nv o l v e th e re tu rn ty pe o f th e se l e cte d f u ncti o n.

If th e ch o i ce i s be tw e e n tw o te m pl ate s, th e n th e m os t s p e c i a l i z e d o f th e te m pl ate s i s pre f e rre d (pro v i de d o ne i s actu al l y m o re spe ci al i z e d th an th e o th e r). S e e S e cti o n 1 2 .2 .2 o n pag e 1 8 6 f o r a th o ro u g h e x pl anati o n o f th i s co nce pt.

B.3.2 Conversion Sequences

A n i m pl i ci t co nv e rsi o n can, i n g e ne ral , be a se q u e nce o f e l e m e ntary co nv e rsi o ns. C o nsi de r th e f o l l o w i ng co de e x am pl e :

class Base { public: operator short() const; }; class Derived : public Base { }; void count(int);

Page 546: CPlusPlus Templates The Complete Guide

void process(Derived const& object) { count(object); // matches with user-defined conversion }

T h e cal l count(object) w o rk s be cau se object can i m pl i ci tl y be co nv e rte d to int. H o w e v e r, th i s co nv e rsi o n re q u i re s se v e ral ste ps:

1. A c o n v e r s i o n o f object f r o m Derived const t o Base const 2 . A u s e r -d e f i n e d c o n v e r s i o n o f t h e r e s u l t i n g Base const o b j e c t t o t y p e short 3 . A p r o m o t i o n o f short t o int

T h i s i s th e m o st g e ne ral k i nd o f co nv e rsi o n se q u e nce : a standard co nv e rsi o n (a de ri v e d-to -base co nv e rsi o n, i n th i s case ), f o l l o w e d by a u se r-de f i ne d co nv e rsi o n, f o l l o w e d by ano th e r standard co nv e rsi o n. A l th o u g h th e re can be at m o st o ne u se r-de f i ne d co nv e rsi o n i n a co nv e rsi o n se q u e nce , i t i s al so po ssi bl e to h av e o nl y standard co nv e rsi o ns.

A n i m po rtant pri nci pl e o f o v e rl o ad re so l u ti o n i s th at a co nv e rsi o n se q u e nce th at i s a su bse q u e nce o f ano th e r co nv e rsi o n se q u e nce i s pre f e rabl e o v e r th e l atte r se q u e nce . If th e re w e re an addi ti o nal candi date f u ncti o n

void count(short);

i n th e e x am pl e , i t w o u l d be pre f e rre d f o r th e cal l count(object) be cau se i t do e sn' t re q u i re th e th i rd ste p (pro m o ti o n) i n th e co nv e rsi o n se q u e nce .

B.3.3 Pointer Conversions

P o i nte rs and po i nte rs to m e m be rs u nde rg o v ari o u s spe ci al standard co nv e rsi o ns, i ncl u di ng

• C o nv e rsi o ns to ty pe bool • C o nv e rsi o ns f ro m an arbi trary po i nte r ty pe to void* • D e ri v e d-to -base co nv e rsi o ns f o r po i nte rs • B ase -to -de ri v e d co nv e rsi o ns f o r po i nte rs to m e m be rs

A l th o u g h al l o f th e se can cau se a " m atch w i th standard co nv e rsi o ns o nl y , " th e y are no t rank e d e q u al l y .

F i rst, co nv e rsi o ns to ty pe bool (bo th f ro m a re g u l ar po i nte r and f ro m a po i nte r to a m e m be r) are co nsi de re d w o rse th an any o th e r k i nd o f standard co nv e rsi o n. F o r e x am pl e :

void check(void*); // (1) void check(bool); // (2)

Page 547: CPlusPlus Templates The Complete Guide

void rearrange (Matrix* m) { check(m); // calls (1) … }

W i th i n th e cate g o ry o f re g u l ar po i nte r co nv e rsi o ns, a co nv e rsi o n to ty pe void* i s co nsi de re d w o rse th an a co nv e rsi o n f ro m a de ri v e d cl ass po i nte r to a base cl ass po i nte r. F u rth e rm o re , i f v i abl e f u ncti o ns to di f f e re nt cl asse s re l ate d by i nh e ri tance e x i st, a co nv e rsi o n to th e m o st de ri v e d o ne i s pre f e rre d. H e re i s ano th e r sh o rt e x am pl e :

class Interface { … }; class CommonProcesses : public Interface { … }; class Machine : public CommonProcesses { … }; char* serialize(Interface*); // (1) char* serialize(CommonProcesses*); // (2) void dump (Machine& machine) { char* buffer = serialize(machine); // calls (2) … }

T h e co nv e rsi o n f ro m Machine* to CommonProcesses* i s pre f e rre d o v e r th e co nv e rsi o n to Interface* , w h i ch i s f ai rl y i ntu i ti v e .

A v e ry si m i l ar ru l e appl i e s to po i nte rs to m e m be rs: B e tw e e n tw o co nv e rsi o ns o f re l ate d po i nte r-to -m e m b e r ty pe s, th e " cl o se st o ne " i n th e i nh e ri tance g raph (th at i s, th e l e ast de ri v e d) i s pre f e rre d.

B.3.4 Functors and Surrogate Functions

W e m e nti o ne d e arl i e r th at af te r th e nam e o f a f u ncti o n h as be e n l o o k e d u p to cre ate an i ni ti al o v e rl o ad se t, th e se t i s tw e ak e d i n v ari o u s w ay s. A n i nte re sti ng si tu ati o n ari se s w h e n a cal l e x pre ssi o n re f e rs to a cl ass ty pe o bj e ct i nste ad o f a f u ncti o n. In th i s case th e re are tw o po te nti al addi ti o ns to th e o v e rl o ad se t.

T h e f i rst addi ti o n i s strai g h tf o rw ard: A ny m e m be r o pe rato r () (th e f u ncti o n cal l o pe rato r) i s adde d to th e se t. O bj e cts w i th su ch o pe rato rs are u su al l y cal l e d

Page 548: CPlusPlus Templates The Complete Guide

f unc t or s (se e C h apte r 2 2 ).

A l e ss o bv i o u s addi ti o n o ccu rs w h e n a cl ass ty pe o bj e ct co ntai ns an i m pl i ci t co nv e rsi o n o pe rato r to a po i nte r to a f u ncti o n ty pe (o r to a re f e re nce to a f u ncti o n ty pe ). [3 ] In su ch si tu ati o ns, a du m m y (so -cal l e d s ur r og a t e ) f u ncti o n i s adde d to th e o v e rl o ad se t. T h i s su rro g ate f u ncti o n candi date i s co nsi de re d to h av e an i m pl i e d param e te r o f th e ty pe de si g nate d by th e co nv e rsi o n f u ncti o n, i n addi ti o n to param e te rs w i th ty pe s co rre spo ndi ng to th e param e te r ty pe s i n th e de sti nati o n ty pe o f th at co nv e rsi o n f u ncti o n. A n e x am pl e m ak e s th i s m u ch cl e are r:

[3 ] T h e co nv e rsi o n o pe rato r m u st al so be appl i cabl e i n th e se nse th at, f o r e x am pl e , a no n-const o pe rato r i s no t co nsi de re d f o r const o bj e cts.

typedef void FuncType(double, int); class IndirectFunctor { public: … operator()(double, double); operator FuncType*() const; }; void activate(IndirectFunctor const& funcObj) { funcObj(3, 5); // ERROR: ambiguous! }

T h e cal l funcObj(3, 5) i s tre ate d as a cal l w i th th re e arg u m e nts: funcObj , 3, and 5. T h e v i abl e f u ncti o n candi date s i ncl u de th e m e m be r operator () (w h i ch i s tre ate d as h av i ng param e te r ty pe s IndirectFunctor&, double , and double) and a su rro g ate f u ncti o n w i th param e te rs o f ty pe FuncType*, double , and int. T h e su rro g ate f u ncti o n h as a w o rse m atch f o r th e i m pl i e d param e te r (be cau se i t re q u i re s a u se r-de f i ne d co nv e rsi o n), bu t i t h as a be tte r m atch f o r th e l ast param e te r; h e nce th e tw o candi date s canno t be o rde re d. T h e cal l i s th e re f o re am bi g u o u s.

S u rro g ate f u ncti o ns are i n th e m o st o bscu re co rne rs o f C + + and rare l y o ccu r i n practi ce (f o rtu nate l y ).

B.3.5 Other Overloading Contexts

S o f ar w e h av e di scu sse d o v e rl o adi ng i n th e co nte x t o f de te rm i ni ng w h i ch f u ncti o n sh o u l d be cal l e d i n a cal l e x pre ssi o n. H o w e v e r, th e re are a f e w o th e r co nte x ts i n w h i ch a si m i l ar se l e cti o n m u st be m ade .

T h e f i rst co nte x t o ccu rs w h e n th e addre ss o f a f u ncti o n i s ne e de d. C o nsi de r th e

Page 549: CPlusPlus Templates The Complete Guide

f o l l o w i ng e x am pl e :

int n_elements(Matrix const&); // (1) int n_elements(Vector const&); // (2) void compute() { … int (*funcPtr)(Vector const&) = n_elements; // selects (2) … }

H e re , th e nam e n_elements re f e rs to an o v e rl o ad se t, bu t o nl y th e addre ss o f o ne f u ncti o n i n th at se t i s de si rabl e . O v e rl o ad re so l u ti o n th e n atte m pts to m atch th e re q u i re d f u ncti o n ty pe (th e ty pe o f funcPtr i n th i s e x am pl e ) to th e av ai l abl e candi date s.

T h e o th e r co nte x t th at re q u i re s o v e rl o ad re so l u ti o n i s i ni t i a l i z a t i on. U nf o rtu nate l y , th i s i s a to pi c f rau g h t w i th su btl e ti e s th at are be y o nd w h at can be co v e re d i n an appe ndi x . H o w e v e r, a si m pl e e x am pl e at l e ast i l l u strate s th i s addi ti o nal aspe ct o f o v e rl o ad re so l u ti o n:

#include <string> class BigNum { public: BigNum(long n); BigNum(double n); BigNum(std::string const&); … operator double(); operator long(); … }; void initDemo() { BigNum bn1(100103); BigNum bn2("7057103224.095764"); int in = bn1; }

In th i s e x am pl e , o v e rl o ad re so l u ti o n i s ne e de d to se l e ct th e appro pri ate co nstru cto r o r co nv e rsi o n o pe rato r. In th e v ast m aj o ri ty o f case s, th e o v e rl o adi ng ru l e s pro du ce th e i ntu i ti v e re su l t. H o w e v e r, th e de tai l s o f th e se ru l e s are q u i te co m pl e x , and so m e appl i cati o ns re l y o n so m e o f th e m o re o bscu re co rne rs i n th i s are a o f th e C + + l ang u ag e (f o r e x am pl e , th e de si g n o f std::auto_ptr).

Page 550: CPlusPlus Templates The Complete Guide

Bibliography

T h i s appe ndi x l i sts th e re so u rce s th at w e re m e nti o ne d, ado pte d, o r ci te d i n th i s bo o k . T h e se day s m any o f th e adv ance m e nts i n pro g ram m i ng h appe n i n e l e ctro ni c f o ru m s. It i s th e re f o re no t su rpri si ng to f i nd, i n addi ti o n to th e m o re tradi ti o nal bo o k s and arti cl e s, q u i te a f e w W e b si te s. W e ce rtai nl y do no t cl ai m th at o u r l i st i s cl o se to be i ng co m pre h e nsi v e . H o w e v e r, w e do f i nd th at th e y are re l e v ant co ntri bu ti o ns to th e to pi c o f C + + te m pl ate s.

W e b si te s are ty pi cal l y co nsi de rabl y m o re v o l ati l e th an bo o k s and arti cl e s. T h e Inte rne t l i nk s l i ste d h e re m ay no t be v al i d i n th e f u tu re . T h e re f o re , w e pro v i de th e actu al l i st o f l i nk s f o r th i s bo o k at th e f o l l o w i ng si te (and w e e x pe ct th i s si te to be stabl e ):

h ttp://w w w .j o su tti s.co m /tm pl bo o k

B e f o re l i sti ng th e bo o k s, arti cl e s, and W e b si te s, w e i ntro du ce th e m o re i nte racti v e k i nd o f re so u rce s th at are pro v i de d by so -cal l e d ne w s g r oup s .

Page 551: CPlusPlus Templates The Complete Guide

Newsgroups

U s e ne t i s a l arg e and di v e rse co l l e cti o n o f e l e ctro ni c f o ru m s o f te n cal l e d ne w s g r oup s . S o m e o f th e se ne w sg ro u ps are m ode r a t e d , w h i ch m e ans th at e v e ry su bm i ssi o n i s e x am i ne d i n so m e w ay f o r i ts appro pri ate ne ss.

A f e w U se ne t g ro u ps are de di cate d to th e di scu ssi o n o f th e C + + l ang u ag e . In f act, m any o f th e m o st adv ance d te ch ni q u e s pre se nte d i n th i s bo o k w e re f i rst pu bl i sh e d i n so m e o f th e se g ro u ps. In so m e case s, te ch ni q u e s w e re de v e l o pe d th ro u g h co l l abo rati v e di scu ssi o n i n th e se g ro u ps.

T h e f o l l o w i ng U se ne t ne w sg ro u ps di scu ss C + + , th e standard, and th e C + + standard l i brary :

• T u to ri al l e v e l C + + (u nm o de rate d) •

alt.comp.lang.learn.c-c++

• G e ne ral aspe cts o f C + + (u nm o de rate d) •

comp.lang.c++

• G e ne ral aspe cts o f C + + (m o de rate d) •

comp.lang.c++.moderated

• A spe cts o f th e C + + standard (m o de rate d) •

comp.std.c++

If y o u do n' t h av e acce ss to a U se ne t ne w sg ro u ps se rv e r, y o u can u se th e G o o g l e U se ne t arch i v e :

h ttp://g ro u ps.g o o g l e .co m

Page 552: CPlusPlus Templates The Complete Guide

Books and Web Sites

[ A l e x a ndr e s c uD e s i g n] A ndre i A l e x andre scu M ode r n C + + D e s i g n G e ne ri c P ro g ram m i ng and D e si g n P atte rns A ppl i e d A ddi so n-W e sl e y , R e adi ng , M A , 2 0 0 1

[ A us t e r nS T L ] M atth e w H . A u ste rn G e ne r i c P r og r a m m i ng a nd t h e S T L U si ng and E x te ndi ng th e C + + S tandard T e m pl ate L i brary A ddi so n-W e sl e y , R e adi ng , M A , 1 9 9 9

[ B C C L ] J e re m y S i e k T h e B oos t C onc e p t C h e c k L i b r a r y h ttp://w w w .bo o st.o rg /l i bs/co nce pt_ ch e ck /co nce pt_ ch e ck .h tm

[ B l i t z + + ] T o dd V e l dh u i z e n B l i t z + + : O b j e c t -O r i e nt e d S c i e nt i f i c C om p ut i ng h ttp://w w w .o o nu m e ri cs.o rg /bl i tz

[ B oos t ] T h e B oos t R e p os i t or y f or F r e e , P e e r -R e v i e w e d C + + L i b r a r i e s h ttp://w w w .bo o st.o rg

[ B oos t C om p os e ] B oos t C om p os e L i b r a r y h ttp://w w w .bo o st.o rg /l i bs/co m po se

[ B oos t S m a r t P t r ] S m a r t P oi nt e r L i b r a r y h ttp://w w w .bo o st.o rg /l i bs/sm art_ ptr

[ B oos t T yp e T r a i t s ] T yp e T r a i t s L i b r a r y h ttp://w w w .bo o st.o rg /l i bs/ty pe _ trai ts

[ C a r g i l l E x c e p t i onS a f e t y] T o m C arg i l l

Page 553: CPlusPlus Templates The Complete Guide

E x c e p t i on H a ndl i ng : A F a l s e S e ns e of S e c ur i t y A v ai l abl e at: h ttp://w w w .aw pro f e ssi o nal .co m /m e y e rscdde m o /de m o /m ag az i ne /i nde x .h tm C + + R e po rt, No v e m b e r-D e ce m be r 1 9 9 4

[ C op l i e nC R T P ] J am e s O . C o pl i e n C ur i ous l y R e c ur r i ng T e m p l a t e P a t t e r ns C + + R e po rt, F e bru ary 1 9 9 5

[ C or e I s s ue 1 1 5 ] C or e I s s ue 1 1 5 of t h e C + + S t a nda r d h ttp://anu bi s.dk u u g .dk /j tc1 /sc2 2 /w g 2 1 /do cs/cw g _ to c.h tm l

[ C z a r ne c k i E i s e ne c k e r G e nP r og ] K rz y sz to f C z arne ck i , U l ri ch W . E i se ne ck e r G e ne r a t i v e P r og r a m m i ng M e th o ds, T o o l s, and A ppl i cati o ns A ddi so n-W e sl e y , R e adi ng , M A , 2 0 0 0

[ D e s i g nP a t t e r ns G oV ] E ri ch G am m a, R i ch ard H e l m , R al ph J o h nso n, J o h n V l i ssi de sD e s i g n P a t t e r ns E l e m e nts o f R e u sabl e O bj e ct-O ri e nte d S o f tw are A ddi so n-W e sl e y , R e adi ng , M A , 1 9 9 5

[ E D G ] E di so n D e si g n G ro u p C om p i l e r F r ont E nds f or t h e O E M M a r k e t h ttp://w w w .e dg .co m

[ E l l i s S t r ous t r up A R M ] M arg are t A . E l l i s, B j arne S tro u stru p T h e A nnot a t e d C + + R e f e r e nc e M a nua l ( A R M ) A ddi so n-W e sl e y , R e adi ng , M A , 1 9 9 0

[ J os ut t i s A ut oP t r ] Ni co l ai M . J o su tti s a ut o_ p t r a nd a ut o_ p t r _ r e f h ttp://w w w .j o su tti s.co m /l i bbo o k /au to _ ptr.h tm l

[ J os ut t i s O O P ] Ni co l ai M . J o su tti s O b j e c t -O r i e nt e d P r og r a m m i ng i n C + + J o h n W i l e y and S o ns L td, 2 0 0 2

Page 554: CPlusPlus Templates The Complete Guide

[ J os ut t i s S t dL i b ] Ni co l ai M . J o su tti s T h e C + + S t a nda r d L i b r a r y A T u to ri al and R e f e re nce A ddi so n-W e sl e y , R e adi ng , M A , 1 9 9 9

[ K oe ni g M ooA c c ] A ndre w K o e ni g , B arbara E . M o o A c c e l e r a t e d C + + P racti cal P ro g ram m i ng by E x am pl e A ddi so n-W e sl e y , R e adi ng , M A , 2 0 0 0

[ L a m b da L i b ] J aak k o J ä rv i , G ary P o w e l l L L , T h e L a m b d a L i b r a r y h ttp://w w w .bo o st.o rg /l i bs/l am bda/do c

[ L i p p m a nO b j M od] S tanl e y B . L i ppm an I ns i de t h e C + + O b j e c t M ode l A ddi so n-W e sl e y , R e adi ng , M A , 1 9 9 6

[ M e ye r s C ount i ng ] S co tt M e y e rs C ount i ng O b j e c t s I n C + + C /C + + U se rs J o u rnal , A pri l 1 9 9 8

[ M e ye r s E f f e c t i v e ] S co tt M e y e rs E f f e c t i v e C + + 5 0 S pe ci f i c W ay s to Im pro v e Y o u r P ro g ram s and D e si g n (2 nd E di ti o n) A ddi so n-W e sl e y , R e adi ng , M A , 1 9 9 8

[ M e ye r s M or e E f f e c t i v e ] S co tt M e y e rs M or e E f f e c t i v e C + + 3 5 Ne w W ay s to Im pro v e Y o u r P ro g ram s and D e si g ns A ddi so n-W e sl e y , R e adi ng , M A , 1 9 9 6

[ M T L ] A ndre w L u m sdai ne , J e re m y S i e k M T L , T h e M a t r i x T e m p l a t e L i b r a r y h ttp://w w w .o sl .i u .e du /re se arch /m tl

[ M us s e r W a ng D yna V e r i ]

Page 555: CPlusPlus Templates The Complete Guide

D . R . M u sse r, C . W ang D yna m i c V e r i f i c a t i on of C + + G e ne r i c A l g or i t h m s IE E E T ransacti o ns o n S o f tw are E ng i ne e ri ng , V o l . 2 3 , No . 5 , M ay 1 9 9 7

[ M ye r s T r a i t s ] Nath an C . M y e rs T r a i t s : A Ne w a nd U s e f ul T e m p l a t e T e c h ni q ue h ttp://w w w .cantri p.o rg /trai ts.h tm l

[Ne w M a t ] R o be rt D av i e s Ne w M a t 1 0 , A M a t r i x L i b r a r y i n C + + h ttp://w w w .ro be rtnz .co m /nm _ i ntro .h tm

[Ne w S h or t e r O E D ] L e sl i e B ro w n, e t al . T h e Ne w S h or t e r O x f or d E ng l i s h D i c t i ona r y ( f our t h e di t i on) O x f o rd U ni v e rsi ty P re ss, O x f o rd, 1 9 9 3

[ P O O M A ] P O O M A : A H i g h -P e r f or m a nc e C + + T ool k i t f or P a r a l l e l S c i e nt i f i c C om p ut a t i on h ttp://w w w .po o m a.co m

[ S t a nda r d9 8 ] IS O I nf or m a t i on T e c h nol og y—P r og r a m m i ng L a ng ua g e s —C + + D o cu m e nt Nu m be r IS O /IE C 1 4 8 8 2 -1 9 9 8 IS O /IE C 1 9 9 8

[ S t a nda r d0 2 ] IS O I nf or m a t i on T e c h nol og y—P r og r a m m i ng L a ng ua g e s —C + + ( a s a m e nde d b y t h e f i r s t t e c h ni c a l c or r i g e ndum ) D o cu m e nt Nu m be r IS O /IE C 1 4 8 8 2 -2 0 0 2 IS O /IE C , e x pe cte d l ate 2 0 0 2

[ S t r ous t r up C + + P L ] B j arne S tro u stru p T h e C + + P r og r a m m i ng L a ng ua g e , S pe ci al e d. A ddi so n-W e sl e y , R e adi ng , M A , 2 0 0 0

[ S t r ous t r up D nE ] B j arne S tro u stru p T h e D e s i g n a nd E v ol ut i on of C + +

Page 556: CPlusPlus Templates The Complete Guide

A ddi so n-W e sl e y , R e adi ng , M A , 1 9 9 4

[ S t r ous t r up G l os s a r y] B j arne S tro u stru p B j a r ne S t r ous t r up ' s C + + G l os s a r y h ttp://w w w .re se arch .att.co m /~ bs/g l o ssary .h tm l

[ S ut t e r E x c e p t i ona l ] H e rb S u tte r E x c e p t i ona l C + + 4 7 E ng i ne e ri ng P u z z l e s, P ro g ram m i ng P ro bl e m s, and S o l u ti o ns A ddi so n-W e sl e y , R e adi ng , M A , 2 0 0 0

[ S ut t e r M or e E x c e p t i ona l ] H e rb S u tte r M or e E x c e p t i ona l C + + 4 0 Ne w E ng i ne e ri ng P u z z l e s, P ro g ram m i ng P ro bl e m s, and S o l u ti o ns A ddi so n-W e sl e y , R e adi ng , M A , 2 0 0 1

[ U nr uh P r i m e O r i g ] E rw i n U nru h O r i g i na l M e t a p r og r a m f or P r i m e Num b e r C om p ut a t i on h ttp://w w w .e rw i n-u nru h .de /pri m o ri g .h tm l

[ V a nde v oor de S ol ut i ons ] D av i d V ande v o o rde C + + S ol ut i ons A ddi so n-W e sl e y , R e adi ng , M A , 1 9 9 8

[ V e l dh ui z e nM e t a 9 5 ] T o dd V e l dh u i z e n U s i ng C + + T e m p l a t e M e t a p r og r a m s C + + R e po rt, M ay 1 9 9 5

[ V e l dh ui z e nP a p e r s ] T o dd V e l dh u i z e n T odd V e l dh ui z e n' s P a p e r s a nd A r t i c l e s a b out G e ne r i c P r og r a m m i ng a nd T e m p l a t e s h ttp://o sl .i u .e du /~ tv e l dh u i /pape rs

Page 557: CPlusPlus Templates The Complete Guide

Glossary

T h i s g l o ssary i s a co m pi l ati o n o f th e m o st i m po rtant te ch ni cal te rm s th at are to pi c i n th i s bo o k . S e e [S tro u stru pG l o ssary ] f o r a v e ry co m pl e te , g e ne ral g l o ssary o f te rm s u se d by C + + pro g ram m e rs.

abstract class

A c l a s s f o r w h i c h t h e c r e a t i o n o f c o n c r e t e o b j e c t s ( instances ) i s i m p o s s i b l e . Ab s t r a c t c l a s s e s c a n b e u s e d t o c o l l e c t c o m m o n p r o p e r t i e s o f d i f f e r e n t c l a s s e s i n a s i n g l e t y p e o r t o d e f i n e a p o l y m o r p h i c i n t e r f a c e . B e c a u s e a b s t r a c t c l a s s e s a r e u s e d a s b a s e c l a s s e s , t h e a c r o n y m A B C i s s o m e t i m e s u s e d f o r ab str act b ase class.

A D L

An a c r o n y m f o r ar g u m ent-d ep end ent lo o k u p . AD L i s a p r o c e s s t h a t l o o k s f o r a n a m e o f a f u n c t i o n ( o r o p e r a t o r ) i n n a m e s p a c e s a n d c l a s s e s t h a t a r e i n s o m e w a y a s s o c i a t e d w i t h t h e a r g u m e n t s o f t h e f u n c t i o n c a l l i n w h i c h t h a t f u n c t i o n ( o r o p e r a t o r n a m e ) a p p e a r s . F o r h i s t o r i c a l r e a s o n s , i t i s s o m e t i m e s c a l l e d ex tend ed K o enig lo o k u p o r j u s t K o enig lo o k u p ( t h e l a t t e r i s a l s o u s e d f o r A D L a p p l i e d t o o p e r a t o r s o n l y ) .

an g le brack e t h ack

A n o n s t a n d a r d f e a t u r e t h a t a l l o w s a c o m p i l e r t o a c c e p t t w o c o n s e c u t i v e > c h a r a c t e r s a s t w o c l o s i n g ang le b r ack ets ( e v e n t h o u g h t h e y n o r m a l l y r e q u i r e i n t e r v e n i n g w h itesp ace ) . F o r e x a m p l e , t h e e x p r e s s i o n vector<list<int>> i s n o t v a l i d C + + b u t i s t r e a t e d i d e n t i c a l l y t o vector<list<int> > b y t h e a n g l e b r a c k e t h a c k .

an g le brack e ts

T h e c h a r a c t e r s < a n d > w h e n t h e y a r e u s e d t o d e l i m i t a l i s t o f t e m p l a t e a r g u m e n t s o r t e m p l a t e p a r a m e t e r s .

A N S I

An a c r o n y m f o r A m er ican N atio nal S tand ar d I nstitu te. A p r i v a t e , n o n p r o f i t o r g a n i z a t i o n t h a t c o o r d i n a t e s e f f o r t s t o p r o d u c e s t a n d a r d s p e c i f i c a t i o n s o f a l l k i n d s . A s u b c o m m i t t e e c a l l e d J 16 i s a d r i v i n g f o r c e b e h i n d t h e s t a n d a r d i z a t i o n o f C + + . I t c o o p e r a t e s c l o s e l y w i t h t h e i n t e r n a t i o n a l s t a n d a r d s o r g a n i z a t i o n ( I S O ) .

Page 558: CPlusPlus Templates The Complete Guide

arg u m e n t

A v a l u e ( i n a b r o a d s e n s e ) t h a t s u b s t i t u t e s a p ar am eter o f a p r o g r a m m a t i c e n t i t y . F o r e x a m p l e , i n a f u n c t i o n c a l l abs(-3) t h e a r g u m e n t i s -3. I n s o m e p r o g r a m m i n g c o m m u n i t i e s ar g u m ents a r e c a l l e d actu al p ar am eter s ( w h e r e a s p ar am eter s a r e c a l l e d f o r m al p ar am eter s ) .

arg u m e n t-d e p e n d e n t lo o k u p S e e [A D L ]

class

T h e d e s c r i p t i o n o f a c a t e g o r y o f o b j e c t s . T h e c l a s s d e f i n e s a s e t o f c h a r a c t e r i s t i c s f o r a n y o b j e c t . T h e s e i n c l u d e i t s d a t a ( attr ib u tes , d ata m em b er s ) a s w e l l a s i t s o p e r a t i o n s ( m eth o d s , m em b er f u nctio ns ) . I n C + + , c l a s s e s a r e s t r u c t u r e s w i t h m e m b e r s t h a t c a n a l s o b e f u n c t i o n s a n d a r e s u b j e c t t o a c c e s s l i m i t a t i o n s . T h e y a r e d e c l a r e d u s i n g t h e k e y w o r d s class o r struct.

class te m p late

A c o n s t r u c t t h a t r e p r e s e n t s a f a m i l y o f c l a s s e s . I t s p e c i f i e s a p a t t e r n f r o m w h i c h a c t u a l c l a s s e s c a n b e g e n e r a t e d b y s u b s t i t u t i n g t h e t e m p l a t e p a r a m e t e r s b y s p e c i f i c e n t i t i e s . C l a s s t e m p l a t e s a r e s o m e t i m e s c a l l e d " p ar am eter iz ed " classes , a l t h o u g h t h i s t e r m i s m o r e g e n e r a l .

class ty p e

A C + + t y p e d e c l a r e d w i t h class , struct, o r union.

co lle cti o n class

A c l a s s t h a t i s u s e d t o m a n a g e a g r o u p o f o b j e c t s . I n C + + , c o l l e c t i o n c l a s s e s a r e a l s o c a l l e d co ntainer s.

co n stan t-e x p re ssi o n

An e x p r e s s i o n w h o s e v a l u e i s c o m p u t e d a t c o m p i l e t i m e b y t h e c o m p i l e r . W e s o m e t i m e s c a l l t h i s a tr u e co nstant t o a v o i d c o n f u s i o n w i t h co nstant ex p r essio n ( w i t h o u t h y p h e n ) . T h e l a t t e r i n c l u d e s e x p r e s s i o n s t h a t a r e c o n s t a n t b u t c a n n o t b e c o m p u t e d a t c o m p i l e t i m e b y t h e c o m p i l e r .

Page 559: CPlusPlus Templates The Complete Guide

const m e m be r f u n cti o n

A m e m b e r f u n c t i o n t h a t c a n b e c a l l e d f o r c o n s t a n t a n d t e m p o r a r y o b j e c t s b e c a u s e i t d o e s n o t n o r m a l l y m o d i f y m e m b e r s o f t h e *this o b j e c t .

co n tai n e r S e e [co lle cti o n class]

co n v e rsi o n o p e rato r

A s p e c i a l m e m b e r f u n c t i o n t h a t d e f i n e s h o w a n o b j e c t c a n i m p l i c i t l y ( o r e x p l i c i t l y ) b e c o n v e r t e d t o a n o b j e c t o f a n o t h e r t y p e . I t i s d e c l a r e d u s i n g t h e f o r m operator ty p e().

C R T P

An a c r o n y m f o r cu r io u sly r ecu r r ing tem p late p atter n. T h i s r e f e r s t o a c o d e p a t t e r n w h e r e a c l a s s X d e r i v e s f r o m a b a s e c l a s s t h a t h a s X a s a t e m p l a t e a r g u m e n t .

cu ri o u sly re cu rri n g te m p late p atte rn S e e [C R T P ]

d e cay

T h e i m p l i c i t c o n v e r s i o n o f a n a r r a y o r a f u n c t i o n t o a p o i n t e r . F o r e x a m p l e , t h e s t r i n g l i t e r a l "Hello" h a s t y p e char const[6] , b u t i n m a n y C + + c o n t e x t s i t i s i m p l i c i t l y c o n v e r t e d t o a p o i n t e r o f t y p e char const* ( w h i c h p o i n t s t o t h e f i r s t c h a r a c t e r o f t h e s t r i n g ) .

d e clarati o n

A C + + c o n s t r u c t t h a t i n t r o d u c e s o r r e i n t r o d u c e s a n a m e i n t o a C + + s c o p e .

S e e al so [d e f i n i ti o n ]

d e d u cti o n

T h e p r o c e s s t h a t i m p l i c i t l y d e t e r m i n e s t e m p l a t e a r g u m e n t s f r o m t h e c o n t e x t i n w h i c h t e m p l a t e a r e u s e d . T h e c o m p l e t e t e r m i s tem p late ar g u m ent d ed u ctio n.

d e f i n i ti o n

Page 560: CPlusPlus Templates The Complete Guide

A d eclar atio n t h a t m a k e s t h e d e t a i l s o f t h e d e c l a r e d e n t i t y k n o w n o r , i n t h e c a s e o f v a r i a b l e s , t h a t f o r c e s s t o r a g e s p a c e t o b e r e s e r v e d f o r t h e d e c l a r e d e n t i t y . F o r c l a s s t y p e s a n d f u n c t i o n d e f i n i t i o n s , t h i s a m o u n t s t o d e c l a r a t i o n s t h a t i n c l u d e a b r a c e -e n c l o s e d b o d y . F o r e x t e r n a l v a r i a b l e d e c l a r a t i o n s , t h i s m e a n s e i t h e r a d e c l a r a t i o n w i t h n o extern k e y w o r d o r a d e c l a r a t i o n w i t h a n i n i t i a l i z e r .

d e p e n d e n t base class

A b a s e c l a s s t h a t d e p e n d s o n a t e m p l a t e p a r a m e t e r . S p e c i a l c a r e m u s t b e t a k e n t o a c c e s s m e m b e r s o f d e p e n d e n t b a s e c l a s s e s .

S e e al so [tw o -p h ase lo o k u p ]

d e p e n d e n t n am e

A n a m e t h e m e a n i n g o f w h i c h d e p e n d s o n a t e m p l a t e p a r a m e t e r . F o r e x a m p l e , A<T>::x i s a d e p e n d e n t n a m e w h e n A o r T i s a t e m p l a t e p a r a m e t e r . T h e n a m e o f a f u n c t i o n i n a f u n c t i o n c a l l i s a l s o d e p e n d e n t i f a n y o f t h e a r g u m e n t s i n t h e c a l l h a s a t y p e t h a t d e p e n d s o n a t e m p l a t e p a r a m e t e r . F o r e x a m p l e , f i n f((T*)0) i s d e p e n d e n t i f T i s a t e m p l a t e p a r a m e t e r . T h e n a m e o f a t e m p l a t e p a r a m e t e r i s n o t c o n s i d e r e d d e p e n d e n t , h o w e v e r .

S e e al so [tw o -p h ase lo o k u p ]

d i g rap h

A c o m b i n a t i o n o f t w o c o n s e c u t i v e c h a r a c t e r s t h a t a r e e q u i v a l e n t t o a n o t h e r s i n g l e c h a r a c t e r i n C + + c o d e . T h e p u r p o s e o f d i g r a p h s i s t o a l l o w t h e i n p u t o f C + + s o u r c e c o d e w i t h k e y b o a r d s t h a t l a c k c e r t a i n c h a r a c t e r s . Al t h o u g h t h e y a r e u s e d r e l a t i v e l y r a r e l y , t h e d i g r a p h <: i s s o m e t i m e s a c c i d e n t a l l y f o r m e d w h e n a l e f t ang le b r ack et i s f o l l o w e d b y a s c o p e r e s o l u t i o n o p e r a t o r ( :: ) w i t h o u t t h e r e q u i r e d i n t e r v e n i n g w h itesp ace.

d o t-C f i le

A f i l e i n w h i c h d ef initio ns o f v a r i a b l e s a n d n o n i n l i n e f u n c t i o n s a r e l o c a t e d . M o s t o f t h e e x e c u t a b l e ( a s o p p o s e d t o d e c l a r a t i v e ) c o d e o f a p r o g r a m i s n o r m a l l y p l a c e d i n d o t -C f i l e s . T h e y a r e n a m e d d o t-C f i l e s b e c a u s e t h e y a r e u s u a l l y n a m e d w i t h a s u f f i x s u c h a s .cpp , .C , .c, .cc, o r .cxx. S e e a l s o h ead er f ile a n d tr anslatio n u nit.

E B C O

An a c r o n y m f o r em p ty b ase class o p tim iz atio n. An o p t i m i z a t i o n p e r f o r m e d b y m o s t m o d e r n c o m p i l e r s w h e r e b y a n " e m p t y " b a s e c l a s s s u b o b j e c t d o e s n o t o c c u p y a n y s t o r a g e .

Page 561: CPlusPlus Templates The Complete Guide

e m p ty base class o p ti m i z ati o n S e e [E B C O ]

e x p li ci t i n stan ti ati o n d i re cti v e

A C + + c o n s t r u c t t h e s o l e p u r p o s e o f w h i c h i s t o c r e a t e a P O I .

e x p li ci t sp e ci ali z ati o n

A c o n s t r u c t t h a t d e c l a r e s o r d e f i n e s a n a l t e r n a t i v e d e f i n i t i o n f o r a s u b s t i t u t e d t e m p l a t e . T h e o r i g i n a l ( g e n e r i c ) t e m p l a t e i s c a l l e d t h e p r im ar y tem p late. I f t h e a l t e r n a t i v e d e f i n i t i o n s t i l l d e p e n d s o n o n e o r m o r e t e m p l a t e p a r a m e t e r s , i t i s c a l l e d a p ar tial sp ecializ atio n. O t h e r w i s e , i t i s a f u ll sp ecializ atio n.

e x p re ssi o n te m p late

A c l a s s t e m p l a t e u s e d t o r e p r e s e n t a p a r t o f a n e x p r e s s i o n . T h e t e m p l a t e i t s e l f r e p r e s e n t s a p a r t i c u l a r k i n d o f o p e r a t i o n . T h e t e m p l a t e p a r a m e t e r s s t a n d f o r t h e k i n d s o f o p e r a n d s t o w h i c h t h e o p e r a t i o n a p p l i e s .

f ri e n d n am e i n j e cti o n

T h e p r o c e s s t h a t m a k e s a f u n c t i o n n a m e v i s i b l e w h e n i t i s d e c l a r e d o n l y f r i e n d .

f u ll sp e ci ali z ati o n S e e [e x p li ci t sp e ci ali z ati o n ]

f u n cti o n o bj e ct S e e [f u n cto r]

f u n cti o n te m p late

A c o n s t r u c t t h a t r e p r e s e n t s a f a m i l y o f f u n c t i o n s . I t s p e c i f i e s a p a t t e r n f r o m w h i c h a c t u a l f u n c t i o n s c a n b e g e n e r a t e d b y s u b s t i t u t i n g t h e t e m p l a t e p a r a m e t e r s b y s p e c i f i c e n t i t i e s . N o t e t h a t a f u n c t i o n t e m p l a t e i s a t e m p l a t e a n d n o t a f u n c t i o n . F u n c t i o n t e m p l a t e s a r e s o m e t i m e s c a l l e d " p ar am eter iz ed " f u nctio ns , a l t h o u g h t h e l a t t e r t e r m i s m o r e g e n e r a l .

f u n cto r

An o b j e c t ( a l s o c a l l e d a f u nctio n o b j ect ) t h a t c a n b e c a l l e d u s i n g t h e f u nctio n call sy ntax . I n C + + ,

Page 562: CPlusPlus Templates The Complete Guide

t h e s e a r e p o i n t e r s o r r e f e r e n c e s t o f u n c t i o n s a n d c l a s s e s w i t h a m e m b e r o p e r a t o r ().

h e ad e r f i le

A f i l e m e a n t t o b e c o m e p a r t o f a t r a n s l a t i o n u n i t t h r o u g h a #include d i r e c t i v e . S u c h f i l e s o f t e n c o n t a i n d eclar atio ns o f v a r i a b l e s a n d f u n c t i o n s t h a t a r e r e f e r r e d t o f r o m m o r e t h a n o n e t r a n s l a t i o n u n i t , a s w e l l a s d ef initio ns o f t y p e s , i n l i n e f u n c t i o n s , t e m p l a t e s , c o n s t a n t s , a n d m a c r o s . T h e y a r e u s u a l l y n a m e d w i t h a s u f f i x l i k e .hpp , .h, .H , .hh, o r .hxx. T h e y a r e a l s o c a l l e d inclu d e f iles.

S e e al so [d o t-C f i le ] S e e al so [tran slati o n u n i t]

i n clu d e f i le S e e [h e ad e r f i le ]

i n d i re ct call

A f u n c t i o n c a l l f o r w h i c h t h e c a l l e d f u n c t i o n i s n o t k n o w n u n t i l t h e c a l l a c t u a l l y o c c u r s ( a t r u n t i m e ) .

i n i ti ali z e r

A c o n s t r u c t t h a t s p e c i f i e s h o w t o i n i t i a l i z e a n a m e d o b j e c t . F o r e x a m p l e , i n

std::complex<float> z1 = 1.0, z2(0.0, 1.0);

t h e i n i t i a l i z e r s a r e = 1.0 a n d (0.0, 1.0).

i n i ti ali z e r li st

A c o m m a - s e p a r a t e d l i s t o f e x p r e s s i o n s e n c l o s e d i n b r a c e s u s e d t o i n i t i a l i z e o b j e c t s ( o r a r r a y s ) . I n c o n s t r u c t o r s i t c a n b e u s e d t o d e f i n e v a l u e s t o i n i t i a l i z e m e m b e r s a n d b a s e c l a s s e s .

i n j e cte d class n am e

T h e n a m e o f a c l a s s a s i t i s v i s i b l e i n i t s o w n s c o p e . F o r c l a s s t e m p l a t e s , t h e n a m e o f t h e t e m p l a t e i s t r e a t e d w i t h i n t h e s c o p e o f t h e t e m p l a t e a s a c l a s s n a m e i f t h e n a m e i s n o t f o l l o w e d b y a t e m p l a t e a r g u m e n t l i s t .

i n stan ce

Page 563: CPlusPlus Templates The Complete Guide

T h e t e r m instance h a s t w o m e a n i n g s i n C + + p r o g r a m m i n g : T h e m e a n i n g t h a t i s t a k e n f r o m t h e o b j e c t -o r i e n t e d t e r m i n o l o g y i s an instance o f a class : An o b j e c t t h a t i s t h e r e a l i z a t i o n o f a c l a s s . F o r e x a m p l e , i n C + + , std::cout i s a n i n s t a n c e o f t h e c l a s s std::ostream. T h e o t h e r m e a n i n g ( a n d t h e o n e t h a t i s a l m o s t a l w a y s i n t e n d e d i n t h i s b o o k ) i s a tem p late instance : A c l a s s , a f u n c t i o n , o r a m e m b e r f u n c t i o n o b t a i n e d b y s u b s t i t u t i n g a l l t h e t e m p l a t e p a r a m e t e r s b y s p e c i f i c v a l u e s . I n t h i s s e n s e , a n instance i s a l s o c a l l e d a sp ecializ atio n , a l t h o u g h t h e l a t t e r t e r m i s o f t e n m i s t a k e n f o r ex p licit sp ecializ atio n.

i n stan ti ati o n

T h e p r o c e s s o f c r e a t i n g a r e g u l a r c l a s s , f u n c t i o n , o r m e m b e r f u n c t i o n f r o m a t e m p l a t e b y s u b s t i t u t i n g t e m p l a t e p a r a m e t e r s w i t h a c t u a l v a l u e s . T h e a l t e r n a t i v e s e n s e o f c r e a t i n g a n instance ( o b j e c t ) o f a c l a s s i s n o t u s e d i n t h i s b o o k

S e e al so [( i n stan ce ) ]

I S O

W o r l d - w i d e a c r o n y m f o r I n t e r n a t i o n a l O r g a n i z a t i o n f o r S t a n d a r d i z a t i o n . An I S O w o r k g r o u p c a l l e d W G 2 1 i s a d r i v i n g f o r c e b e h i n d t h e e f f o r t s t o s t a n d a r d i z e a n d d e v e l o p C + + .

i te rato r

An o b j e c t t h a t k n o w s h o w t o t r a v e r s e a s e q u e n c e o f e l e m e n t s . O f t e n , t h e s e e l e m e n t s b e l o n g t o a c o l l e c t i o n

S e e al so [( co lle cti o n class) ]

li n k able e n ti ty

A n o n i n l i n e f u n c t i o n o r m e m b e r f u n c t i o n , a g l o b a l v a r i a b l e , o r a s t a t i c d a t a m e m b e r , i n c l u d i n g a n y s u c h t h i n g s g e n e r a t e d f r o m a t e m p l a t e .

lv alu e

I n t h e o r i g i n a l C l a n g u a g e , a n e x p r e s s i o n w a s c a l l e d a n lv alu e i f i t c o u l d a p p e a r o n t h e lef t o f a n a s s i g n m e n t o p e r a t o r . C o n v e r s e l y , a n e x p r e s s i o n t h a t c o u l d a p p e a r o n l y o n t h e r i g h t o f a n a s s i g n m e n t o p e r a t o r w a s c a l l e d a n r v alu e. T h i s d e f i n i t i o n i s n o l o n g e r a p p r o p r i a t e i n m o d e r n C a n d C + + . I n s t e a d a n lv alu e c a n b e t h o u g h t o f a s a l o c a t o r v al u e : An e x p r e s s i o n t h a t d e s i g n a t e s a n o b j e c t b y n a m e o r a d d r e s s ( p o i n t e r , r e f e r e n c e , o r a r r a y a c c e s s ) r a t h e r t h a n b y p u r e c o m p u t a t i o n . L v a l u e s n e e d n o t b e m o d i f i a b l e ( f o r e x a m p l e , t h e n a m e o f a c o n s t a n t o b j e c t i s a no nm o d if iab le lv alu e) . Al l e x p r e s s i o n s t h a t a r e n o t l v a l u e s a r e r v alu es. I n p a r t i c u l a r , t e m p o r a r y o b j e c t s c r e a t e d

Page 564: CPlusPlus Templates The Complete Guide

e x p l i c i t l y ( T() ) o r a s t h e r e s u l t o f f u n c t i o n c a l l s a r e r v a l u e s .

m e m be r class te m p late

A c o n s t r u c t t h a t r e p r e s e n t s a f a m i l y o f m e m b e r c l a s s e s . I t i s a c l a s s t e m p l a t e d e c l a r e d i n s i d e a n o t h e r c l a s s o r c l a s s t e m p l a t e . I t h a s i t s o w n s e t o f t e m p l a t e p a r a m e t e r s ( u n l i k e a m e m b e r c l a s s o f a c l a s s t e m p l a t e ) .

m e m be r f u n cti o n te m p late

A c o n s t r u c t t h a t r e p r e s e n t s a f a m i l y o f m e m b e r f u n c t i o n s . I t h a s i t s o w n s e t o f t e m p l a t e p a r a m e t e r s ( u n l i k e a m e m b e r f u n c t i o n o f a c l a s s t e m p l a t e ) . I t i s v e r y s i m i l a r t o a f u n c t i o n t e m p l a t e , b u t w h e n a l l t h e t e m p l a t e p a r a m e t e r s a r e s u b s t i t u t e d , t h e r e s u l t i s a m e m b e r f u n c t i o n ( i n s t e a d o f a n o r d i n a r y f u n c t i o n ) . M e m b e r f u n c t i o n t e m p l a t e s c a n n o t b e v i r t u a l .

m e m be r te m p late

A m em b er class tem p late o r a m em b er f u nctio n tem p late.

n o n d e p e n d e n t n am e

A n a m e t h a t i s n o t d e p e n d e n t o n a t e m p l a t e p a r a m e t e r .

S e e al so [d e p e n d e n t n am e ] S e e al so [tw o -p h ase lo o k u p ]

O D R

An a c r o n y m f o r o ne-d ef initio n r u le. T h i s r u l e p l a c e s s o m e r e s t r i c t i o n s o n t h e d ef initio ns t h a t a p p e a r i n a C + + p r o g r a m . S e c t i o n 7 .4 o n p a g e 9 0 a n d Ap p e n d i x A f o r d e t a i l s .

o n e -d e f i n i ti o n ru le S e e [O D R ]

o v e rlo ad re so lu ti o n

T h e p r o c e s s t h a t s e l e c t s w h i c h f u n c t i o n t o c a l l w h e n s e v e r a l c a n d i d a t e s ( u s u a l l y a l l h a v i n g t h e s a m e n a m e ) e x i s t .

Page 565: CPlusPlus Templates The Complete Guide

p aram e te r

A p l a c e h o l d e r e n t i t y t h a t i s m e a n t t o b e s u b s t i t u t e d w i t h a n a c t u a l " v a l u e " ( a n ar g u m ent ) a t s o m e p o i n t . F o r m a c r o p a r a m e t e r s a n d t e m p l a t e p a r a m e t e r s , t h e s u b s t i t u t i o n o c c u r s a t c o m p i l e t i m e . F o r f u n c t i o n c a l l p a r a m e t e r s i t h a p p e n s a t r u n t i m e . I n s o m e p r o g r a m m i n g c o m m u n i t i e s p ar am eter s a r e c a l l e d f o r m al p ar am eter s ( w h e r e a s ar g u m ents a r e c a l l e d actu al p ar am eter s ) .

S e e al so [arg u m e n t]

p aram e te ri z e d class

A c l a s s t e m p l a t e o r a c l a s s n e s t e d i n a c l a s s t e m p l a t e . B o t h a r e p ar am eter iz ed b e c a u s e t h e y d o n o t c o r r e s p o n d t o a u n i q u e c l a s s u n t i l t h e t e m p l a t e a r g u m e n t s h a v e b e e n s p e c i f i e d .

p aram e te ri z e d f u n cti o n

A f u n c t i o n o r m e m b e r f u n c t i o n t e m p l a t e o r a m e m b e r f u n c t i o n o f a c l a s s t e m p l a t e . Al l a r e p ar am eter iz ed b e c a u s e t h e y d o n o t c o r r e s p o n d t o a u n i q u e f u n c t i o n ( o r m e m b e r f u n c t i o n ) u n t i l t h e t e m p l a t e a r g u m e n t s h a v e b e e n s p e c i f i e d .

p arti al sp e ci ali z ati o n

A c o n s t r u c t t h a t d e c l a r e s o r d e f i n e s a n a l t e r n a t i v e d e f i n i t i o n f o r c e r t a i n s u b s t i t u t i o n s o f a t e m p l a t e . T h e o r i g i n a l ( g e n e r i c ) t e m p l a t e i s c a l l e d t h e p r i m ar y tem p late. T h e a l t e r n a t i v e d e f i n i t i o n s t i l l d e p e n d s o n t e m p l a t e p a r a m e t e r s . C u r r e n t l y , t h i s c o n s t r u c t e x i s t s o n l y f o r c l a s s t e m p l a t e s .

S e e al so [e x p li ci t sp e ci ali z ati o n ]

P O D

An a c r o n y m f o r " p l a i n o l d d a t a ( t y p e ) ." P O D t y p e s a r e t y p e s t h a t c a n b e d e f i n e d w i t h o u t c e r t a i n C + + f e a t u r e s ( l i k e v i r t u a l m e m b e r f u n c t i o n s , a c c e s s k e y w o r d s , a n d s o f o r t h ) . F o r e x a m p l e , e v e r y o r d i n a r y C struct i s a P O D .

P O I

An a c r o n y m f o r p o int o f instantiatio n. A P O I i s a l o c a t i o n i n t h e s o u r c e c o d e w h e r e a t e m p l a t e ( o r a m e m b e r o f a t e m p l a t e ) i s c o n c e p t u a l l y e x p a n d e d b y s u b s t i t u t i n g t e m p l a t e p a r a m e t e r s w i t h t e m p l a t e a r g u m e n t s . I n p r a c t i c e , t h i s e x p a n s i o n d o e s n o t n e e d t o o c c u r a t e v e r y P O I .

S e e al so [e x p li ci t i n stan ti ati o n d i re cti v e ]

Page 566: CPlusPlus Templates The Complete Guide

p o i n t o f i n stan ti ati o n S e e [P O I ]

p o li cy class

A c l a s s o r c l a s s t e m p l a t e t h e m e m b e r s o f w h i c h d e s c r i b e c o n f i g u r a b l e b e h a v i o r f o r a g e n e r i c c o m p o n e n t . P o l i c i e s a r e n o r m a l l y p a s s e d a s t e m p l a t e a r g u m e n t s . F o r e x a m p l e , a s o r t i n g t e m p l a t e m a y h a v e a n o r d e r i n g p o l i c y . P o licy classes a r e a l s o c a l l e d p o licy tem p lates o r j u s t p o licies.

S e e al so [trai ts te m p late ]

p o ly m o rp h i sm

T h e a b i l i t y o f a n o p e r a t i o n ( w h i c h i s i d e n t i f i e d b y i t s n a m e ) t o a p p l y t o o b j e c t s o f d i f f e r e n t k i n d s . I n C + + , t h e t r a d i t i o n a l o b j e c t -o r i e n t e d c o n c e p t o f p o l y m o r p h i s m ( a l s o c a l l e d r u n-tim e o r d y nam ic p o l y m o r p h i s m ) i s a c h i e v e d t h r o u g h v i r t u a l f u n c t i o n s t h a t a r e o v e r r i d d e n i n d e r i v e d c l a s s e s . I n a d d i t i o n , C + + t e m p l a t e s e n a b l e s o -c a l l e d static p o l y m o r p h i s m .

p re co m p i le d h e ad e r

A p r o c e s s e d f o r m o f s o u r c e c o d e t h a t c a n q u i c k l y b e l o a d e d b y t h e c o m p i l e r . T h e s o u r c e c o d e u n d e r l y i n g a p r e c o m p i l e d h e a d e r m u s t b e t h e f i r s t p a r t o f a tr anslatio n u nit ( i n o t h e r w o r d s , i t c a n n o t s t a r t s o m e w h e r e i n t h e m i d d l e o f a t r a n s l a t i o n u n i t ) . O f t e n , a p r e c o m p i l e d h e a d e r c o r r e s p o n d s t o a n u m b e r o f h e a d e r f i l e s . U s i n g p r e c o m p i l e d h e a d e r s c a n s u b s t a n t i a l l y i m p r o v e t h e t i m e n e e d e d t o b u i l d a l a r g e a p p l i c a t i o n w r i t t e n i n C + + .

p ri m ary te m p late

A t e m p l a t e t h a t i s n o t a p ar tial sp ecializ atio n.

q u ali f i e d n am e

A n a m e c o n t a i n i n g a s c o p e q u a l i f i e r ( ::) .

re f e re n ce co u n ti n g

A r e s o u r c e m a n a g e m e n t s t r a t e g y t h a t k e e p s c o u n t o f h o w m a n y e n t i t i e s a r e r e f e r r i n g t o a p a r t i c u l a r r e s o u r c e . W h e n t h e c o u n t d r o p s t o z e r o , t h e r e s o u r c e c a n b e d i s p o s e d o f .

Page 567: CPlusPlus Templates The Complete Guide

rv alu e S e e [lv alu e ]

so u rce f i le

A h ead er f ile o r a d o t-C f ile.

sp e ci ali z ati o n

T h e r e s u l t o f s u b s t i t u t i n g t e m p l a t e p a r a m e t e r s b y a c t u a l v a l u e s . A s p e c i a l i z a t i o n m a y b e c r e a t e d b y a n instantiatio n o r b y a n ex p licit sp ecializ atio n. T h i s t e r m i s s o m e t i m e s m i s t a k e n l y e q u a t e d w i t h ex p licit sp ecializ atio n.

S e e al so [i n stan ce ]

te m p late

A c o n s t r u c t t h a t r e p r e s e n t s a f a m i l y o f c l a s s e s o r f u n c t i o n s . I t s p e c i f i e s a p a t t e r n f r o m w h i c h a c t u a l c l a s s e s o r f u n c t i o n s c a n b e g e n e r a t e d b y s u b s t i t u t i n g t h e t e m p l a t e p a r a m e t e r s b y s p e c i f i c e n t i t i e s . I n t h i s b o o k , t h e t e r m d o e s n o t i n c l u d e f u n c t i o n s , c l a s s e s , a n d s t a t i c d a t a m e m b e r s t h a t a r e p a r a m e t e r i z e d o n l y b y v i r t u e o f b e i n g m e m b e r s o f a c l a s s t e m p l a t e .

S e e al so [class te m p late ]

te m p late arg u m e n t

T h e " v a l u e " s u b s t i t u t e d f o r a tem p late p ar am eter . T h i s " v a l u e " i s u s u a l l y a t y p e , a l t h o u g h c e r t a i n c o n s t a n t v a l u e s a n d t e m p l a t e s c a n b e v a l i d t e m p l a t e a r g u m e n t s t o o .

te m p late arg u m e n t d e d u cti o n S e e [d e d u cti o n ]

te m p late -i d

T h e c o m b i n a t i o n o f a t e m p l a t e n a m e f o l l o w e d b y tem p late ar g u m ents i n ang le b r ack ets ( f o r e x a m p l e , std::list<int> ) .

te m p late p aram e te r

A g e n e r i c p l a c e h o l d e r i n a t e m p l a t e . T h e m o s t c o m m o n k i n d o f t e m p l a t e p a r a m e t e r a r e ty p e p ar am eter s , w h i c h r e p r e s e n t t y p e s . N o nty p e p ar am eter s r e p r e s e n t c o n s t a n t v a l u e s o f a c e r t a i n t y p e , a n d tem p late tem p late p ar am eter s r e p r e s e n t c l a s s t e m p l a t e s .

Page 568: CPlusPlus Templates The Complete Guide

trai ts te m p late

A t e m p l a t e t h e m e m b e r s o f w h i c h d e s c r i b e c h a r a c t e r i s t i c s ( t r a i t s ) o f t h e t e m p l a t e a r g u m e n t s . U s u a l l y t h e p u r p o s e o f t r a i t s t e m p l a t e s i s t o a v o i d a n e x c e s s i v e n u m b e r o f t e m p l a t e p a r a m e t e r s .

S e e al so [p o li cy class]

tran slati o n u n i t

A d o t-C f i l e w i t h a l l t h e h e a d e r f i l e s a n d s t a n d a r d l i b r a r y h e a d e r s i t i n c l u d e s u s i n g #include d i r e c t i v e s , m i n u s t h e p r o g r a m t e x t t h a t i s e x c l u d e d b y c o n d i t i o n a l c o m p i l a t i o n d i r e c t i v e s s u c h a s #if.F o r s i m p l i c i t y , i t c a n a l s o b e t h o u g h t o f a s t h e r e s u l t o f p r e p r o c e s s i n g a d o t-C f i l e .

S e e al so [d o t-C f i le ] S e e al so [h e ad e r f i le ]

tru e co n stan t S e e [co n stan t-e x p re ssi o n . ]

tu p le

A g e n e r a l i z a t i o n o f t h e C struct c o n c e p t s u c h t h a t m e m b e r s c a n b e a c c e s s e d b y n u m b e r .

tw o -p h ase lo o k u p

T h e n a m e l o o k u p m e c h a n i s m u s e d f o r n a m e s i n t e m p l a t e . T h e " t w o p h a s e s " a r e ( 1) t h e p h a s e d u r i n g w h i c h a t e m p l a t e d e f i n i t i o n i s f i r s t e n c o u n t e r e d b y a c o m p i l e r , a n d ( 2 ) t h e i n s t a n t i a t i o n o f a t e m p l a t e . N o nd ep end ent nam es a r e l o o k e d u p o n l y i n t h e f i r s t p h a s e , b u t d u r i n g t h i s f i r s t p h a s e no nd ep end ent b ase classes a r e n o t c o n s i d e r e d . D ep end ent nam es w i t h a s c o p e q u a l i f i e r ( :: ) a r e l o o k e d u p o n l y i n t h e s e c o n d p h a s e . D e p e n d e n t n a m e s w i t h o u t a s c o p e q u a l i f i e r m a y b e l o o k e d u p i n b o t h p h a s e s , b u t i n t h e s e c o n d p h a s e o n l y a r g u m e n t -d e p e n d e n t l o o k u p i s p e r f o r m e d .

u se r-d e f i n e d co n v e rsi o n

A t y p e c o n v e r s i o n d e f i n e d b y t h e p r o g r a m m e r . I t c a n b e a co nstr u cto r t h a t c a n b e c a l l e d w i t h o n e a r g u m e n t o r a co nv er sio n o p er ato r . U n l e s s i t i s a c o n s t r u c t o r d e c l a r e d w i t h t h e k e y w o r d explicit , t h e t y p e c o n v e r s i o n c a n o c c u r i m p l i c i t l y .

w h i te sp ace

I n C + + t h i s i s t h e s p a c e t h a t d e l i m i t s t h e t o k e n s ( i d e n t i f i e r s , l i t e r a l s , s y m b o l s , a n d s o o n ) i n s o u r c e

Page 569: CPlusPlus Templates The Complete Guide

c o d e . B e s i d e s t h e t r a d i t i o n a l b l a n k s p a c e , n e w l i n e , a n d h o r i z o n t a l t a b u l a t i o n c h a r a c t e r s , t h i s a l s o i n c l u d e s c o m m e n t s . O t h e r w h i t e s p a c e c h a r a c t e r s ( f o r e x a m p l e , t h e p a g e f e e d c o n t r o l c h a r a c t e r ) a r e s o m e t i m e s a l s o v a l i d w h i t e s p a c e .