0% found this document useful (0 votes)
272 views

CPlusPlus Templates The Complete Guide

Uploaded by

doibungnenomyeu
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
272 views

CPlusPlus Templates The Complete Guide

Uploaded by

doibungnenomyeu
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 569

• T a b le o f C o n t e n t s

C++ Templates: The Complete Guide


B yD a v id V a n d e v o o r d e , N ic o la i M . J o s u t t is

P u b lis h e r : A d d is o n W e s le y
P u b D a te : N o v e m b e r 1 2, 20 0 2
IS 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
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 + + .
• T a b le o f C o n t e n t s

C++ Templates: The Complete Guide


B yD a v id V a n d e v o o r d e , N ic o la i M . J o s u t t is

P u b lis h e r : A d d is o n W e s le y
P u b D a te : N o v e m b e r 1 2, 20 0 2
IS 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 fa c e
A c k n o w le d g m e n t s
N ic o 's A c k n o w le d g m e n t s
D a v id 's A c k n o w le d g m e n t s

C h a p t e r 1 . A b o u t T h is 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 in g T h is 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 is 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 ic 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 ir s t L o o k a t F u n c t io n T e m p la 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
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 la s s T e m p la 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 ic k yB a s ic 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 in g T e m p la t e s in P r a c t ic 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 ic T e m p la t e T e r m in o lo 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
P a r t I I : T e m p la t e s in D e p t h
C h a p t e r 8 . F u n d a m e n t a ls in 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 in T e m p la 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 ia t io 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 ia t io 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 la t e A r g u m e n t D e d u c t io 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 ic C o d e " D o e s n 't Q u it 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 ir e c t io 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
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 la 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 ia t io n D ia g n o s t ic 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 II : T e m p la t e s a n d D e s ig 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 ig 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 it s a n d P o lic y C la 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 la t e s a n d I n h e r it 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 te r 1 7 . M e ta p r o g r a m s
S e c t i o n 1 7 .1 . A F ir s t E x a m p le 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
S e c t i o n 1 7 .3 . A S e c o n d E x a m p le : C o m p u t in 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 io n T e m p la 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 IV : A d v a n c e d A p p lic a t io 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
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 io n s : A C o m p le t e I m p le m e n t a t io 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 ix B . O v e r lo a d R e s o lu t io 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 ib lio 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 it e s

G lo s s a r y
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 .


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
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!
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 .
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 .
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 im and P h u ong Sh arp , G reg g V au g h n, and J oh n W i eg ley.
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 .
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 .
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.
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 /.
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]
[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
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.
1.5 The Standard versus Reality

T h eC + + 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.
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.
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 .
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 im p le m e n t t h e s a m e b e h a v io r a g a in a n d a g a in fo r e a c h ty p e t h a t n e e d s
th is b e h a v io 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 ia 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 in , y o u r e in v e n t t h e w h e e l.Y o u m a k e
th e s a m e m is t a k e s a n d y o u t e n d to a v o id c o m p lic a te d b u t b e t t e r a lg o r ith m s
b e c a u s e t h e y le a d t o e v e n m o r e m is ta 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 ia l b a s e
c la s s e s , w h ic h m a k e s it m o r e d iffic u lt to m a in ta in 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 lo s e th e
a d v a n t a g e o f fo r m a tt e d s o u r c e c o d e .C o d e is r e p la c e d b y s o m e " s tu p id t e x t
r e p la c e m e n t m e c h a n is m " t h a t h a s n o id e a o f s c o p e a n d ty 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 .
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 .
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
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
doubles , and once for two std::strings . E ach ti m e, th e m ax i m u m is
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
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&);


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 ith o u t in s t a n t ia tio n , th e t e m p la te c o d e its e lf is c h e c k e d fo 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 is c o v e r e d , s u c h a s m is s in g s e m ic o lo 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 lls a r e d is 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 io n c a lls .

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 .
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 tc h :
2.
max(static_cast<double>(4),4.2) // OK

3 . S p e c ify ( o r q u a lify ) e x p lic it ly t h e t y p e o f T :


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

5 . S p e c ify th a t t h e p a r a m e t e r s m a y h a v e d iffe 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.


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&.

Y ou are not allowed to retu rn v alu es by reference i f th ey are


[4 ]

local to a fu ncti on becau s e you ' d retu rn s om eth i ng th at does n' t


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>


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 .


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
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;
}
// 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)
{
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 ints
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;
}
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.
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 .
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.
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
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>


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
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
}

};
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
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 floats or ev en s tack s


of ints :

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 .
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


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
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).
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
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.


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
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
}
}

W i th

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

you declare a s tack for doubles th at u s es a std::deque<> to m anag e th e


elem ents i nternally.
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 .
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.
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
++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()
{
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.
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
m ay be neces s ary to be p ortable.
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
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.
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 .
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 .
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;
}
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 .
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 ).
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.
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 in t e r n a l c o n t a in e r fo r t h e e le m e n ts .A g a in , th is is a c o n s e q u e n c e
o f th e im p le m e n t a tio n o f t h e n e w a s s ig n m e n t o p e r a to 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 ints to a s tack of


floats :
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 floats , 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();
}

// 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.
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


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 :
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>
#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
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();
}
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 .
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
}

};
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
}
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
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 .


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.
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).
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"
// 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"
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
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 .
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();
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 la t e d e c l a r a t io n a n d d e f in it io n
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
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


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
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 is is 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
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 .
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.
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
#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


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.
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;
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
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;
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
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 .
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
<< ")\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;
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
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
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.
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] ).
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 eC + + 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 .
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.
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 .
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.
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>


class S {};

i s i n fact a defi ni ti on.


7.4 The One-Definition Rule

T h eC + + 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.
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
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 .
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 eC + + 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
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 .
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
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)


{
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]
:

T h ey are m u ch li k e ordi nary clas s m em bers , bu t th ey are


[1]

occas i onally (erroneou s ly) referred to as memb er templates.

1. D e fin itio n s o f m e m b e r f u n c t io n s o f c la s s t e m p la t e s
2 . D e f in it io n s o f n e s t e d c la s s m e m b e r s o f c la s s t e m p la t e s
3 . D e fin itio n s o f s t a t ic d a t a m e m b e r s o f c la s s t e m p la 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
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 inC + + 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>


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).
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:
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 :

T em p late tem p late p aram eters do not denote typ es ei th er;


[3 ]

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
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.
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>
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
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
}

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
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 .
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 la s s e s a n d e n u m e r a tio n s ( in o th e r w o r d s , ty p e s d e c la r e d in a fu n c tio n d e fin itio n ) c a n n o t b e


in v o lv e d in te m p la te ty p e a r g u m e n ts .
2 . Ty p e s t h a t i n v o l v e u n n a m e d c la s s t y p e s o r u n n a m e d e n u m e r a t io n t y p e s c a n n o t b e t e m p la te t y p e
a r g u m e n t s ( u n n a m e d c la s s e s o r e n u m e r a tio n s t h a t a r e g iv e n a n a m e t h r o u g h a ty p e d e f d e c la r a t io 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;
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
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 is
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


• 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
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;
};

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 fu n c tio n g e n e r a t e d fr o m a m e m b e r f u n c t io n te m p la te n e v e r o v e r r id e s a v ir t u a l fu n c tio n .
2 . A c o n s tr u c to r g e n e r a t e d fr o m a c o n s t r u c t o r t e m p la t e is n e v e r a d e f a u lt c o p y c o n s t r u c t o r .( S im ila r ly ,
a n a s s ig n m e n t g e n e r a te d fr o m a n a s s ig 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 is is le s s p r o n e to p r o b le m s b e c a u s e u n lik e c o p y c o n s tr u c t o r s , a s s ig n m e n t o p e r a to 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 .)
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 fr ie n d d e c la r a tio n m a y b e t h e o n ly d e c la r a tio n o f a n e n tity .


2 . A fr ie n d fu n c tio n d e c la r a tio n c a n b e a d e fin itio 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);
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 is n 't q u a lifie d ( in o t h e r w o r d s , it d o e s n 't c o n t a in a d o u b le c o lo n ) , it n e v e r r e f e r s t o a


te m p la te in s t a n c e .I f n o m a tc h in g n o n te m p la t e fu n c tio n is v is ib le a t t h e p o in t o f th e fr ie 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 fin itio 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
fu n c tio n te m p la t e .A m a t c h in g fu n c tio n is p r e f e r r e d o v e r a m a t c h in g fu n c tio n te m p la t e .H o w e v e r ,
s u c h a fr ie n d d e c la r a t io n c a n n o t b e a d e fin itio 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 .
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
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.
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.
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
aC + + 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 + + .
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 if ie d n a m e if th e s c o p e to w h ic h it b e lo n g s is e x p lic itly d e n o t e d u s in 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 is a d e p e n d e n t n a m e if it d e p e n d s in s o m e w a y o n a t e m p la te p a r a m e te r .F o r e x a m p le ,
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 if Tis a k n o w n t y p e d e f ( fo 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- T h e k eyword operator followed by th e s ym bol for an
fu ncti on-i d 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- U s ed to denote u s er-defi ned i m p li ci t conv ers i on op erator—for
fu ncti on-i d 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
(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 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
nam e 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 A nam e th at dep ends i n s om e way on a tem p late p aram eter.
nam e 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 A nam e th at i s not a dep endent nam e by th e abov e des cri p ti on.
nam e

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 .
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]
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
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";
}
}

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
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
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 .
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 + + is
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
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
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


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 in a te m p la te
2 . I s q u a lifie d
3 . I s n o t u s e d a s in a lis t o f b a s e c la s s s p e c ific a t io n s o r in a lis t o f m e m b e r in itia liz e r s in t r o d u c in g a
c o n s t r u c t o r d e f in it io n
4 . I s d e p e n d e n t o n a t e m p la te p a r a m e te 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 ]
:

F rom [V andev oordeSolu ti ons ] , p rov i ng once and for all th at C + +


[5 ]

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 typenames 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
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 ]
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.

T h i s i s actu ally not totally clear from th e tex t of th e s tandard,


[6 ]

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


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


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.
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)


{
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.
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() {
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.
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
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.

I roni cally, th e fi rs t of th es e i m p lem entati ons h ad been


[10 ]

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.
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 + + .
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
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 .
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
};

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
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.
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.

B es i de tw o-phase look u p, term s s u ch


[5 ]
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:
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
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)
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:
// 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
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.

A declarati on contex t i s th e collecti on of all declarati ons


[7 ]

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)
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)
{
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 .
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:


// 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 —


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 es 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 is
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


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 ia liz a t io n is a v a ila b le : I n t h is c a s e , in s t a n t ia t io n o c c u r s , a n d t h e r e s u ltin g s p e c ia liz a t io n is


e n te r e d in th e d a t a b a s e .
2 . A s p e c ia liz a tio n is a v a ila b le b u t is 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 in c e it w a s
g e n e r a te d .H e r e , t o o , in s t a n t ia tio n o c c u r s , b u t t h e r e s u lt in g s p e c ia liz a tio n r e p la c e s t h e o n e
p r e v io u s ly s to r e d in th 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
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 ile t h e s o u r c e s w it h o u t in s t a n t ia t in g a n y r e q u ir e d lin k a b le s p e c ia liz a t io 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 in e w h e t h e r a n y a r e th e
r e s u lt o f m is s in g in s t a n t ia t io n s . I f s o , t h e p r e lin k e r in v o k e s t h e c o m p ile r o n s o u r c e s t h a t c o n t a in t h e
n e e d e d t e m p la t e d e f in it io n s , w it h o p t io n s t o g e n e r a t e t h e m is s in g in s t a n t ia t io n s .
4 . R e p e a t s t e p 3 if a n y d e fin itio 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
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
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 ile c o m p ilin g t h e s o u r c e o f a t r a n s la t io n u n it , 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


if o n e e x is t s a n d c r e a te s t h e in s t a n tia tio n s d ir e c te d t h e r e in .A t t h e s a m e tim e , it w rite s w h ic h p o in ts
o f in s ta n tia t io n it c o u ld h a v e h o n o r e d to th e o b je c t file r e s u lt in g fr o m t h is c o m p ila tio 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 is f ile is c o m p ile 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
file s th a t p a r tic ip a t e in th e lin k s t e p .F o r e a c h in s ta n tia t io n t h a t h a s n o t y e t b e e n g e n e r a te d , th e
r e q u ir 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 ir e c t iv 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 ile s , a n d t h e p r e lin k e r it e r a t io n r e p e a t s .
4 . W h e n c lo s u r e is b e e n a c h ie v e d , a s in g le a c t u a l lin k s t e p is p e r fo 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.
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 eC + + 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
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:
// 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()
{
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>();
}
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"
#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."
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 .
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
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]
(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.
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
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.)
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.
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 .
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
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
}
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);
}
};

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) {
}
};

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.
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 ).
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 .
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
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 tr a in te r fa c e a n d m u s t b e c a r e fu l to u s e it w h e n
p o s s ib le .
2 . G e n e r ic a lg o r it h m s c a n g e n e r a lly n o t d is c r im in a t e b e t w e e n v a r io u s p o s s ib ilitie s . F o r e x a m p le :
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
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++);
}
}
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).
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
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 ic h it w a s
g e n e r a te 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 it in w h ic h t h e n a m e is d e c la 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 ith s u c h a q u a lifie 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 te d fr o m a fu n c tio n t e m p la t e )
5 . I ts r e t u r n t y p e , if th e fu n c t io n is g e n e r a t e d fr o m a fu n c tio n te m p la te
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 , if t h e fu n c tio n is g e n e r a t e d fr o m a f u n c tio n
te m p la te

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);
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";
}
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*)
{
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
tem p late p aram eter as follows :

1. R e p la c e e a c h te m p la te ty p e p a r a m e t e r w ith a u n iq u e " m a d e u p " ty p e .


2 . R e p la c e e a c h te m p la te te m p la t e p a r a m e t e r w it h a u n iq u e " m a d e u p " c la s s t e m p la t e .
3 . R e p la c e e a c h n o n t y p e t e m p la te p a r a m e t e r w ith a u n iq u e " m a d e u p " v a lu e o f t h e a p p r o p r ia t e ty 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
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
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";
}
};
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)
};
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 is
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;
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


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)
{
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:


#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
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 {
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; };
};
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 Lists 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 Lists 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 ali 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
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 Lists 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 in g p a r a m e t e r s o f t h e p r im a r y t e m p la te .
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 im a r y c la s s t e m p la t e a r e u s e d in 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 Nis a t e m p la 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 in g ) to t h e lis t o f p a r a m e t e r s o f th e p r im a r y te m p la 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
// 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
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.
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 .
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 .
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;


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.
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.
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);
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 .
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:
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 ).
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
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.
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
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 .
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
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.
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 :
// 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.
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>,
: typename Kill = defaultKill<T> >
class Mutator {

};
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 .
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
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;
*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.
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.
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
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 .
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; }
};

// 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);

};
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);

};
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.
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,
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 .
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.
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.
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).
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;

};
// 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;
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.
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
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
}
}
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.
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 ]
:

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


[3 ]

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 inC + + 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
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 inC + + :

• 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).
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


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
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)
{
// 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 .
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 : Iterators 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
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.
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.
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():
// 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
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 is
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;
};
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


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
#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 :



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;
}
};
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])
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
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 ]

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


[5 ]

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
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.
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).
• 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


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
#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
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.
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>
#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
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(…);
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: ";
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;
}

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:

T h e h andli ng of volatile and const volatile q u ali fi ers i s


[8 ]

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;
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;
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 :


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:
// 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)
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 .

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
[9 ]

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.
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 nC 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:
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 {
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
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
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;
}
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) {


// 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
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 ).
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
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] ).
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 .
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;
// 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 {
};
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 ]

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 + +


[2 ]

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 ] .
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.
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 if


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
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:
// 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
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
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;
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 .
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 .
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;
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 ).
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
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.
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.
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.
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
m etap rog ram m i ng .

1. 3N = 3 * 3N -1

2 . 3 =
0
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.
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.
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


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 .
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


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
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,
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;
};

#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 .
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
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
#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 ).
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


fe 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.
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 double
Trouble<1>::LongType Doublify<double,double>
Trouble<2>::LongType Doublify<Doublify<double,double>,
Doublify<double,double> >
Trouble<3>::LongType Doublify<Doublify<Doublify<double,double>,
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 .
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)
<< '\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;
}
};

// 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:
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.
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 ]
:

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


[ 3 ]

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;
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).
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 .
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
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

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 lic a tio n o f a n o p e r a t o r ( e x c e p t a s s ig n m e n t ) c r e a t e s a t le a s t o n e t e m p o r a r y a r r a y ( th a t is ,
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 ll t h e a llo w a b le t e m p o r a r y c o p y e lim in a t io n s ) .
2 . E v e r y a p p lic a tio n o f a n o p e r a t o r r e q u ir e s a d d itio n a l tr a v e r s a ls o f th e a r g u m e n t a n d r e s u lt a r r a y s
( a p p r o x i m a t e l y 6 , 0 0 0 doubles 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:
// 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
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.
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


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 {
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 sy 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;
};
};

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 be 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 be 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
};
// 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 be 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:
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 sy 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
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())
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*:
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


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


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
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()));
}
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);
}

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.
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 be 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
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


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]).
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.
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.
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 {
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 -
po i nt scal ar ty pe s.
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 be 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 be 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 be 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 be 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;
};
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 be 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).
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.
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 be 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
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


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


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 be 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 .
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


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 fo ra
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.
• 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 .
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 };
};
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>
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&>();
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
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.
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 .
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;
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 .
[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;
}
// 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.

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


[2 ]

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).
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 be 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 be 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) {
}
// 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


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
a r g u m e n t, is c a lle 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 be r f u ncti o n
get_pointer(). B y u si ng th i s m e m be 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();
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


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
#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
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;
}
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.
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-> ();

};

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
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
le 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
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:
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
// (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);
}
}
}
};

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:
[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 .


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;
}
};
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).
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,
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) …
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 be 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 ).
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 .
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]).
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 .
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
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 dC + + 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) {
}
};
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;
}
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
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.
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
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
};

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
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
}
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:
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


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
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 .
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 be r ty pe s T1 and T2, w e
[2 ]
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


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
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;
}
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


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 .
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 be 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.
22.1 Direct, Indirect, and Inline Calls

T y pi cal l y , w h e n a C o rC + + 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
}

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


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.

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


[2 ]

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;
}
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 .
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;
}
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 sy 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
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.
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 be 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 be 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 be 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:


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 be 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
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 ir tu a l fu n c t io n in 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 be 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 :
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.
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


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()
{
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 ld
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 ).
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


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 be 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


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 (… );
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 {
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()
{
// 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
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 .
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:

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


[7 ]

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
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 .
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; \
}

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 be 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,
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;
};

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) {
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 fe 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;
}
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));
}
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
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()));
}
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()));
}
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 be 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 be 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


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 fo 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 be 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:
// 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:
// 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"
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
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;
// 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;
}

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.
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).
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) {
}
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


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


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
#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;
}
};
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 be 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 {
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
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
#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
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)
);
}
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)
<< '\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"
// 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
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 ]).
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 be 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.
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 exporte 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
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).
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 be 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 be r
o pe rato rs, stati c m e m be 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 be 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.
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 be 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 be 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 be 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 {
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
};
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 aC + + 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.
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 be 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
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 ]

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
[3 ]

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()
{
++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)
{
}
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
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 exporte 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"
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.
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.
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.
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
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.


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 be 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 is
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.

It co u l d al so be o f ty pe MyClass volatile& o r MyClass


[1]

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!
}
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)
}
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 be 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.
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);
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)
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 be 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
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


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).
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 .
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 fe 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


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 ig 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 ib r a r ie 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
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 be 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
[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 le r a t e dC + +
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 da 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 fe c t iv 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 ix T e m p la t e L ib 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 ]
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 it 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 ix L ib r a r yin 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 + +
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
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 to c o lle c t c o m m o n p r o p e r tie s o f d iffe r e n t c la s s e s in a s in g le ty p e o r to d e fin e a p o ly m o r p h ic
in t e r fa c e .B e c a u s e a b s tr a c t c la s s e s a r e u s e d a s b a s e c la s s e s , th e a c r o n y m A B Cis s o m e t im 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 ) in n a m e s p a c e s a n d c la s s e s t h a t a r e in s o m e w a y a s s o c ia te d w ith th e a r g u m e n ts o f
th e fu n c t io n c a ll in w h ic h th a t fu n c t io 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 is to r ic a l r e a s o n s , it is
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 lie d t o o p e r a t o r s o n ly ) .

an g le brack e t h ack

An o n s t a n d a r d f e a t u r e t h a t a llo w s a c o m p ile r t o a c c e p t t w o c o n s e c u t iv e >c h a r a c t e r s a s t w o c lo s in 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 le 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 lim it a lis t o f t e m p la t e a r g u m e n t s o r t e m p la t e


p a r a m e te 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 iv in g fo r c e b e h in d t h e s t a n d a r d iz a tio n o f C + + .I t c o o p e r a t e s c lo s e ly w it h th e in t e r n a t io n a l
s ta n d a r d s o r g a n iz a tio n ( I S O ) .
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 ip tio n o f a c a t e g o r y o f o b je c t s .T h e c la s s d e fin e s a s e t o f c h a r a c t e r is tic s fo r a n y o b je 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

Ac o n s tr u c t t h a t r e p r e s e n ts a fa m ily o f c la s s e s .I t s p e c ifie s a p a t t e r n fr o m w h ic h a c t u a l c la 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 it u t in g t h e t e m p la t e p a r a m e t e r s b y s p e c ific e n t itie s .C la s s t e m p la 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 is m o r e g e n e r a l.

class ty p e

AC + + 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

Ac la s s t h a t is u s e d t o m a n a g e a g r o u p o f o b je c t s . I n C + + , c o lle c t io n c la s s e s a r e a ls o c a lle 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 io 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 ile t im e b y t h e c o m p ile r .
const m e m be r f u n cti o n

Am e m b e r f u n c t io n t h a t c a n b e c a lle d fo r c o n s t a n t a n d t e m p o r a r y o b je c t s b e c a u s e it 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

As p e c ia l m e m b e r fu n c tio n t h a t d e fin e s h o w a n o b je c t c a n im p lic it ly ( o r e x p lic itly ) b e c o n v e r t e d t o


a n o b je c t o f a n o th e r t y p e .I t is d e c la r e d u s in g t h e fo 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 iv e s fr o m a b a s e c la s s t h a t h a s Xa s a t e m p la te 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 im p lic it c o n v e r s io n o f a n a r r a y o r a f u n c t io n t o a p o in t e r . F o r e x a m p le , t h e s t r in g lit 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 it is im p lic it ly c o n v e r t e d t o a p o in 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

AC + + c o n s tr u c t t h a t in tr o d u c e s o r r e in tr o d u c e s a n a m e in 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 im p lic itly d e t e r m in e s t e m p la t e a r g u m e n ts fr o m th e c o n t e x t in w h ic h t e m p la t e a r e
u s e d .T h e c o m p le t e te 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
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
fo r c e s s to r a g e s p a c e to b e r e s e r v e d fo r t h e d e c la r e d e n tit y .F o r c la s s t y p e s a n d fu n c tio n d e fin itio n s ,
th is a m o u n ts to 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

Ab a s e c la s s t h a t d e p e n d s o n a t e m p la te p a r a m e te r .S p e c ia l c a r e m u s t b e ta k e n to 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 la 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 Ao r Tis a te m p la te p a r a m e t e r .T h e n a m e o f a fu n c tio n in a fu n c tio n c a ll is
a ls o d e p e n d e n t if a n y o f t h e a r g u m e n t s in t h e c a ll 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 la 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
te m p la te p a r a m e te r is n o t c o n s id 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

Ac o m b in a tio n o f t w o c o n s e c u tiv e c h a r a c t e r s t h a t a r e e q u iv a le n t to a n o t h e r s in g le c h a r a c te r in C + +
c o d e .T h e p u r p o s e o f d ig r a p h s is t o a llo w t h e in p u t o f C + + s o u r c e c o d e w ith k e y b o a r d s t h a t la 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 to d e c la r a tiv 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 file 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 ile r s w h e r e b y a n " e m p t y " b a s e c la 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 .
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

AC + + c o n s tr u c t t h e s o le p u r p o s e o f w h ic h is to c r e a te a P O I .

e x p li ci t sp e ci ali z ati o n

Ac o n s tr u c t t h a t d e c la r e s o r d e fin e s a n a lte r n a t iv e d e fin itio n fo r a s u b s t itu te d t e m p la te .T h e o r ig in 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

Ac la s s te m p la t e u s e d to 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 io n .T h e t e m p la te its e lf r e p r e s e n ts a
p a r tic u la r k in d o f o p e r a tio n .T h e t e m p la t e p a r a m e te r s s ta n d fo r t h e k in d s o f o p e r a n d s t o w h ic h t h e
o p e r a tio n a p p lie 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 fu n c tio n n a m e v is ib le w h e n it is d e c la r e d o n ly fr ie 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

Ac o n s tr u c t t h a t r e p r e s e n ts a fa m ily o f fu n c tio n s .I t s p e c ifie s a p a tt e r n fr o m w h ic h a c t u a l fu n c t io n s


c a n b e g e n e r a te d b y s u b s tit u tin g t h e te m p la te p a r a m e t e r s b y s p e c ific e n t itie s .N o te t h a t a fu n c tio n
te m p la te is a t e m p la t e a n d n o t a fu n c t io n .F u n c tio n t e m p la t e s a r e s o m e tim e s c a lle 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 is 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 + + ,


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 th a n o n e t r a n s la t io 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 lly 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

Afu n c t io n c a ll fo r w h ic h t h e c a lle d fu n c t io n is n o t k n o w n u n t il t h e c a ll a c t u a lly o c c u r s ( a t r u n t im e ) .

i n i ti ali z e r

Ac o n s tr u c t t h a t s p e c ifie s h o w t o in it ia liz e a n a m e d o b je c t .F o r e x a m p le , in

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 tr u c to r s it c a n b e u s e d to d e fin e v a lu e s to in itia liz e m e m b e r s a n d b a s e c la 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 la s s a s it is v is ib le in its o w n s c o p e .F o r c la s s te m p la t e s , t h e n a m e o f t h e t e m p la t e
is t r e a t e d w it h in t h e s c o p e o f t h e t e m p la t e a s a c la s s n a m e if t h e n a m e is n o t f o llo w e d b y a
te m p la te a r g u m e n t lis t.

i n stan ce
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 in g : T h e m e a n in g th a t is t a k e n fr 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 io n o b t a in e d b y s u b s t it u t in g a ll t h e t e m p la t e p a r a m e t e r s b y s p e c ific v a lu e s . I n t h is
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 is o fte n m is ta k e n fo 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 tin g a r e g u la r c la s s , fu n c t io n , o r m e m b e r f u n c t io n fr o m a te m p la te b y
s u b s tit u tin 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 je c t) o f a c la s s is n o t u s e d in th is 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 lle d
W G 2 1is a d r iv in g fo r c e b e h in d t h e e ffo r t s to s t a n d a r d iz e a n d d e v e lo 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 to t r a v e r s e a s e q u e n c e o f e le m e n t s .O fte n , th e s e e le m e n t s b e lo n g to a
c o lle c tio n

S e e al so [( co lle cti o n class) ]

li n k able e n ti ty

An o n in lin e fu n c t io n o r m e m b e r f u n c t io n , a g lo b a l v a r ia b le , o r a s t a t ic d a t a m e m b e r , in c lu d in g a n y
s u c h t h in g s g e n e r a t e d f r o m a t e m p la 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 ig n m e n t o p e r a t o r .C o n v e r s e ly , 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 ig h t o f a n
a s s ig n m e n t o p e r a t o r w a s c a lle 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 lo c a t o r v alu 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 je c t b y n a m e o r a d d r e s s ( p o in t e r , r e fe 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 tio 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
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

Ac o n s tr u c t t h a t r e p r e s e n ts a fa m ily o f m e m b e r c la s s e s .I t is a c la s s te m p la te d e c la r e d in s id e
a n o t h e r c la s s o r c la s s t e m p la te .I t h a s its o w n s e t o f te m p la t e p a r a m e t e r s ( u n lik e a m e m b e r c la s s
o f a c la s s t e m p la te ) .

m e m be r f u n cti o n te m p late

Ac o n s tr u c t t h a t r e p r e s e n ts a fa m ily o f m e m b e r fu n c t io n s .I t h a s its o w n s e t o f te m p la t e p a r a m e t e r s
( u n lik e a m e m b e r fu n c t io n o f a c la s s t e m p la t e ) .I t is v e r y s im ila r t o a f u n c t io n t e m p la t e , b u t w h e n
a ll t h e t e m p la t e p a r a m e t e r s a r e s u b s t it u t e d , t h e r e s u lt is a m e m b e r f u n c t io n ( in s t e a d o f a n o r d in a r y
fu n c tio n ) .M e m b e r fu n c tio n te m p la t e s c a n n o t b e v ir 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

An a m e t h a t is n o t d e p e n d e n t o n a t e m p la te 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


in 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 le c t s w h ic h f u n c t io n t o c a ll w h e n s e v e r a l c a n d id a t e s ( u s u a lly a ll h a v in g t h e s a m e
n a m e ) e x is t.
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 in t.F o r m a c r o p a r a m e t e r s a n d te m p la te p a r a m e t e r s , t h e s u b s titu tio n o c c u r s a t c o m p ile tim 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 lle d fo 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 to a u n iq u e c la s s u n til t h e te m p la t e a r g u m e n t s h a v e b e e n s p e c ifie d .

p aram e te ri z e d f u n cti o n

Afu n c tio 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
te m p la te a r g u m e n t s h a v e b e e n s p e c ifie d .

p arti al sp e ci ali z ati o n

Ac o n s tr u c t t h a t d e c la r e s o r d e fin e s a n a lte r n a t iv e d e fin itio n fo r c e r ta in s u b s titu tio n s o f a t e m p la te .


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. 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 te m p la te p a r a m e t e r s .C u r r e n tly , th is c o n s tr u c t e x is ts o n ly fo r c la s s te m p la 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 ty p e s a r e t y p e s t h a t c a n b e d e fin e d w it h o u t c e r t a in


C + + fe a t u r e s ( lik e v ir t u a l m e m b e r fu n c t io n s , a c c e s s k e y w o r d s , a n d s o fo r t h ) . F o r e x a m p le , e v e r y
o r d in 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 la t e ) is c o n c e p t u a lly e x p a n d e d b y s u b s t it u t in g t e m p la t e p a r a m e t e r s w it h
te m p la te a r g u m e n t s .I n p r a c tic e , th is e x p a n s io 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 ]


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

Ac la s s o r c la s s t e m p la te t h e m e m b e r s o f w h ic h d e s c r ib e c o n fig u r a b le b e h a v io r fo r a g e n e r ic
c o m p o n e n t .P o lic ie s a r e n o r m a lly p a s s e d a s t e m p la t e a r g u m e n t s . F o r e x a m p le , a s o r t in g t e m p la t e
m a y h a v e a n o r d e r in 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 ilit y o f a n o p e r a t io n ( w h ic h is id e n t ifie d b y it s n a m e ) t o a p p ly t o o b j e c t s o f d iff e r e n t k in 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 ly m o r p h is m ) is a c h ie v e d th r o u g h v ir tu a l fu n c t io n s th a t a r e o v e r r id d e n in d e r iv e d c la s s e s .I n
a d d itio 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

Ap r o c e s s e d fo r m o f s o u r c e c o d e t h a t c a n q u ic k ly b e lo a d e d b y t h e c o m p ile 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 in th e m id d le o f a t r a n s la tio n u n it) .O fte n , a p r e c o m p ile d h e a d e r
c o r r e s p o n d s to a n u m b e r o f h e a d e r file s .U s in g p r e c o m p ile d h e a d e r s c a n s u b s t a n t ia lly im p r o v e th e
t im e n e e d e d t o b u ild a la r g e a p p lic a t io n w r it t e n in 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

Ar 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 titie s a r e r e fe r r in g t o a
p a r tic u la 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 to z e r o , th e r e s o u r c e c a n b e d is p o s e d o f.
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 lt o f s u b s t it u t in g t e m p la t e p a r a m e t e r s b y a c t u a l v a lu e s . As p e c ia liz a t io 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 is s o m e tim e s m is ta k e n ly e q u a t e d w ith
ex p licit sp ecializ atio n.

S e e al so [i n stan ce ]

te m p late

Ac o n s tr u c t t h a t r e p r e s e n ts a fa m ily o f c la s s e s o r fu n c tio n s .I t s p e c ifie s a p a t t e r n fr o m w h ic h a c t u a l


c la s s e s o r fu n c tio n s c a n b e g e n e r a te d b y s u b s tit u t in g t h e t e m p la te p a r a m e t e r s b y s p e c ific e n t itie s .
I n t h is b o o k , t h e t e r m d o e s n o t in c lu d e fu n c tio n s , c la s s e s , a n d s t a tic d a t a m e m b e r s t h a t a r e
p a r a m e te r iz e d o n ly b y v ir tu e o f b e in g m e m b e r s o f a c la s s t e m p la 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 ta n t v a lu e s a n d t e m p la te s c a n b e v a lid te m p la te a r g u m e n t s to 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 .
trai ts te m p late

Ate m p la te th e m e m b e r s o f w h ic h d e s c r ib e c h a r a c t e r is tic s ( tr a its ) o f th e t e m p la te a r g u m e n t s .


U s u a lly th e p u r p o s e o f t r a its te m p la te s is t o a v o id a n e x c e s s iv e n u m b e r o f t e m p la te 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 it

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 ir e c t iv e s , m in u s t h e p r o g r a m t e x t t h a t is e x c lu d e d b y c o n d itio n a l c o m p ila tio n d ir e c tiv 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

Ag e n e r a liz a t io 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 lo o k u p m e c h a n is 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 in g w h ic h a t e m p la te d e fin itio n is fir s t e n c o u n t e r e d b y a c o m p ile r , a n d ( 2 ) t h e in s t a n tia tio 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 ly in th e fir s t p h a s e , b u t d u r in g t h is fir 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
lo o k e d u p o n ly in 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 it h o u t a s c o p e q u a lifie r m a y b e lo 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 io n c a n o c c u r im p lic itly .

w h i te sp ace

I n C + + t h is is t h e s p a c e t h a t d e lim it s t h e t o k e n s ( id e n t ifie r s , lit e r a ls , s y m b o ls , a n d s o o n ) in s o u r c e


c o d e .B e s id e s t h e tr a d it io n a l b la n k s p a c e , n e w lin e , a n d h o r iz o n t a l t a b u la t io n c h a r a c t e r s , t h is a ls o
in c lu d e s c o m m e n ts .O th e r w h it e s p a c e c h a r a c t e r s ( fo r e x a m p le , th e p a g e fe e d c o n tr o l c h a r a c t e r ) a r e
s o m e t im e s a ls o v a lid w h it e s p a c e .

You might also like