CPlusPlus Templates The Complete Guide
CPlusPlus Templates The Complete Guide
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
R eaders learn
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
(8 00) 3 8 2-3 4 19
(3 17 ) 5 8 1-3 7 9 3
V andev oorde, D av i d.
p . cm .
Q A 7 6.7 3 .C 15 3 V 3 7 2003
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.
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
Dedication
To K ar i n a
—D av i d
—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.
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 .
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 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 .
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 .
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:
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 .
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
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 .
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:
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
i s eq u i v alent to
[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:
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:
char* a, b;
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 .
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 :
M any th ank s .
Part I: The Basics
Why Templates?
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 .
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 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.
// basics/max.hpp
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 :
// 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) …
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.
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:
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:
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
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 .
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
[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 ).
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 :
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:
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 .
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
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
}
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):
// basics/max3.cpp
#include <iostream>
#include <cstring>
#include <string>
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
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>
int main ()
{
::max(7, 42, 68); // OK
// basics/max4.cpp
• 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
// basics/stack1.hpp
#include <vector>
#include <stdexcept>
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
}
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.
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:
public:
Stack(); // constructor
void push(T const&); // push element
void pop(); // pop element
T top() const; // return top element
};
[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.
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.
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:
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
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:
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:
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
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.
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:
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 .
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:
// 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>::pop ()
{
if (elems.empty()) {
throw std::out_of_range
("Stack<std::string>::pop(): empty stack");
}
elems.pop_back(); // remove last element
}
[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
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 :
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:
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>
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();
}
};
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 :
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;
W i th
Stack<double,std::deque<double> >
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
// basics/stack4.hpp
#include <stdexcept>
// constructor
template <typename T, int MAXSIZE>
Stack<T,MAXSIZE>::Stack ()
: numElems(0) // start with no elements
{
// nothing else to do
}
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 :
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
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:
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
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:
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 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 :
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:
MyClass<s> x; // OK
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::SubType * ptr
// basics/printcoll.hpp
#include <iostream>
class stlcontainer {
…
typedef … iterator; // iterator for read/write access
typedef … const_iterator; // iterator for read access
…
};
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> >();
}
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.
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:
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
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();
}
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 .
// basics/stack5assign.hpp
elems.push_front(tmp.top());
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.
// basics/stack6decl.hpp
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();
}
// basics/stack6assign.hpp
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:
[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.
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 :
[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();
}
};
CONT<T> elems;
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 {
…
};
T em p late tem p late p aram eters for fu ncti on tem p lates are not allowed.
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
…
};
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();
}
#endif // STACK_HPP
// 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
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
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 :
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 :
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>
int main()
{
std::string s;
// basics/max6.cpp
#include <string>
// basics/refnonref.cpp
#include <typeinfo>
#include <iostream>
int main()
{
ref("hello");
nonref("hello");
}
[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 ] ):
• 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 .
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.
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.
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
// 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;
}
// basics/myfirstmain.cpp
#include "myfirst.hpp"
#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 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 .
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 .
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.
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"
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:
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.
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.
// basics/myfirst3.hpp
#ifndef MYFIRST_HPP
#define MYFIRST_HPP
// declaration of template
export
template <typename T>
void print_typeof (T const&);
#endif // MYFIRST_HPP
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:
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.
[2 ]
N ot ev erybody cons i ders th i s c losed -sou r c e ap p roach a p lu s .
// basics/myfirst4.hpp
#ifndef MYFIRST_HPP
#define MYFIRST_HPP
// declaration of template
EXPORT
template <typename T>
void print_typeof (T const&);
#endif // MYFIRST_HPP
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
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 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 .
#include <iostream>
#include <vector>
#include <list>
…
and
#include <list>
#include <vector>
…
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>
…
#include "std.hpp"
…
[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.
#include "std.hpp"
#include "core_data.hpp"
#include "core_algos.hpp"
…
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.
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.
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).
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.
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.
_STL::basic_string<char,_STL::char_traits<char>,
_STL::allocator<char> >
6.6.4 Tracers
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
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;
}
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.
// 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};
// 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";
}
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
[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 .
[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).
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
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 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 .
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 ).
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
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:
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 + + .
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,
• 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.
class DoubleArrayInClass {
public:
double array[10];
};
ArrayInClass<double,10>
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 .
int main()
{
ArrayInClass<double,10> ad;
ad.array[0] = 1.0;
}
[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.
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:
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
or p erh ap s
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 :
class Collection {
template <typename T> // an in-class member class
template
class Node { // definition
…
};
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 :
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
};
I n addi ti on to th e two fu ndam ental k i nds of tem p lates , th ree oth er k i nds of
declarati ons can be p aram eteri z ed u s i ng a s i m i lar notati on. A ll th ree corres p ond
to defi ni ti ons of m em bers of clas s tem p lates [1]
:
1. 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 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 .
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:
int C;
int X;
struct S;
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
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:
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):
[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
…
};
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 :
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:
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.
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:
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:
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 :
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 :
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 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 :
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
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
int main()
{
double value = implicit_cast<double>(-1);
}
int main()
{
apply(&single<int>, 3); // OK
apply(&multi<int>, 7); // ERROR: no single multi<int>
}
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 ):
#define type_has_member_type_X(T) \
(sizeof(test<T>(0)) == 1)
int main()
{
&f<4>; // ERROR: division by zero (SFINAE doesn't apply)
}
int main()
{
return g<1>(); // 1 cannot be bound to int* parameter,
} // but SFINAE principle applies
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 :
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
}
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 :
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;
};
template<typename T>
void templ_func();
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.
template<typename T, T nontype_param>
class C;
class Base {
int i;
} base;
int a[10];
C<int*, &a[0]>* err3; // ERROR: addresses of individual
array
// elements aren't acceptable
either
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
…
}
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.
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:
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 :
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:
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:
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 ).
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
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) .
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 :
[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 .
namespace BigMath {
class BigNumber {
…
};
bool operator < (BigNumber const&, BigNumber const&);
…
}
using BigMath::BigNumber;
// 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
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.
[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.
// 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;
}
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:
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 ;.
x*
identifier, type, 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.
X<1>(0)
(X<1)>0
template<bool B>
class Invert {
public:
static bool const result = !B;
};
void g()
{
bool test = B<(1>0)>::result; // parentheses required!
}
[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.
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 ).
class X {
…
};
[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 ]).
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
};
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
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;
};
template<typename T>
class Shell {
public:
template<int N>
class In {
public:
template<int M>
class Deep {
public:
virtual void f();
};
};
};
p.template Deep<N>::f()
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.
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;
};
class DX : private BX {
public:
BX::f; // access declaration syntax is deprecated
// use using BX::f instead
};
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
};
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
namespace N {
class X {
…
};
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 .
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;
};
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 ):
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."
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…
};
void g (DD<bool>& d)
{
d.f(); // (3) oops?
}
[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
};
// Variation 2:
template<typename T>
class DD2 : public Base<T> {
public:
void f() { Base<T>::basefield = 0; }
};
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
};
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 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.
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.
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.
template<typename T>
class C {
public:
void f(); // (3) member declaration
}; // (4) class template definition
completed
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
int main()
{
candidate(42); // both previous function declarations can be
called
}
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.
[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.
// details/lazy.cpp
[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.
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);
};
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)
[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.
template<typename T>
class S {
public:
T m;
};
// (5)
unsigned long h()
{
// (6)
return (unsigned long)sizeof(S<int>);
// (7)
}
// (8)
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>.
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.
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)
}
// 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;
};
int main()
{
std::cout << max(N::I(7), N::I(42)).v << std::endl; // (3)
}
[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.
// 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)
{
}
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()
{
}
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
}
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 .
[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 + + .
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 :
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 .
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.
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 .
[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 ).
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
template<typename T>
void f(T) throw(T)
{
}
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() {
}
};
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 .
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.
// 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"
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.
// Translation unit 2:
template<typename T> void f()
{
}
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()
{
}
void g() {
f<int>();
}
// Translation unit 2:
template<typename T> void f()
{
}
void g();
int main()
{
g();
}
[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()
{
}
void g()
{
f<int>();
}
10.6 Afternotes
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.
// 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);
}
// File main.cpp:
#include "template.hpp"
#include "template.cpp"
#include "app.hpp"
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 .
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;
}
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);
}
[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 .
double x[20];
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);
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
template<typename T>
void f1(T*);
class S {
public:
void f(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 :
// details/fppm.cpp
template<int N>
void fppm(void (X<N>::*p)(X<N>::I));
int main()
{
fppm(&X<33>::f); // fine: N deduced to be 33
}
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 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);
class S {
public:
template<typename T, int N> operator T[N]&();
};
void g(S s)
{
f(s);
}
template<typename T>
class B<T> {
};
template<typename T>
class D : B<T> {
};
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;
};
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
}
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
[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 + + .
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).
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
}
[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
template<typename T>
class Array {
private:
T* data;
…
public:
Array(Array<T> const&);
Array<T>& operator = (Array<T> const&);
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. …
}
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;
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
// details/funcoverload.hpp
template<typename T>
int f(T)
{
return 1;
}
template<typename T>
int f(T*)
{
return 2;
}
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;
}
1
2
[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.
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 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>
// fine so far
int main()
{
f1<char, char>('a', 'b'); // ERROR: ambiguous
}
// Translation unit 1:
#include <iostream>
void g()
{
f1<char, char>('a', 'b');
}
// Translation unit 2:
#include <iostream>
int main()
{
f1<char, char>('a', 'b');
g();
}
f1(T2, T1)
f1(T1, T2)
#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;
}
#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;
}
1
2
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 :
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 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
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 .
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.
template<typename T>
class Types {
public:
typedef int I;
};
template<>
class S<void> { // (2)
public:
void f();
};
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<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;
};
};
template<>
class Invalid<double>; // ERROR: Invalid<double> already
instantiated!
// Translation unit 1:
template<typename T>
class Danger {
public:
enum { max = 10; };
};
// Translation unit 2:
template<typename T>
class Danger;
template<>
class Danger<void> {
public:
enum { max = 100; };
};
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.
template<typename T>
int f(T) // (1)
{
return 1;
}
template<typename T>
int f(T*) // (2)
{
return 2;
}
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<typename T>
int g(T, T x = 42)
{
return x;
}
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
#endif // TEMPLATE_G_HPP
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.
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<>
class Outer<bool> { // (8)
public:
template<typename U>
class Inner { // (9)
private:
static int count; // (10)
};
void print() const { // (11)
}
};
template<>
int Outer<void>::code = 12;
template<>
void Outer<void>::print()
{
std::cout << "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();
class DefaultInitOnly {
public:
DefaultInitOnly() {
}
private:
DefaultInitOnly(DefaultInitOnly const&); // no copying possible
};
template<typename T>
class Statics {
private:
T sm;
};
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; };
};
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();
}
…
};
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).
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 .
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
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.
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:
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
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>
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.
int main()
{
strange<Buf<16>>2> >(); // the >> token is not an error
}
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<>
void clear (typename Array<int>::ElementT& p); // ERROR
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:
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 :
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.
int main()
{
Diagnoser<"Surprise!">().print();
}
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.
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
#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).
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.
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 :
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:
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 :
// 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);
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 :
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:
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:
class Base {
public:
virtual Base clone();
};
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 {
…
};
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
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
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.
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:
#include <iostream>
int main()
{
std::cout << max(1, 2, 3, 4) << std::endl;
}
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:
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 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):
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:
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.
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:
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:
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());
…
}
class BigValue {
public:
void init();
…
};
class BigValue {
public:
void 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 .
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 :
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
[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 .
// poly/dynahier.hpp
#include "coord.hpp"
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.
// poly/dynapoly.cpp
#include "dynahier.hpp"
#include <vector>
distance(c1,c2); // distance(GeoObj&,GeoObj&)
distance(l,c); // distance(GeoObj&,GeoObj&)
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.
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 .
// poly/statichier.hpp
#include "coord.hpp"
// poly/staticpoly.cpp
#include "statichier.hpp"
#include <vector>
distance(c1,c2); // distance<Circle,Circle>(GeoObj1&,GeoObj2&)
distance(l,c); // distance<Line,Circle>(GeoObj1&,GeoObj2&)
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
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.
• 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.
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.
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 ).
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
…
};
// poly/printmax.cpp
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
#include "MyClass.hpp"
int main()
{
std::vector<MyClass> c1;
std::list<MyClass> c2;
…
print_max (c1);
print_max (c2);
}
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 ).
Bag c1;
Set c2;
…
Iterator i1(s);
Iterator i2(b);
…
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 .
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
[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
#endif // ACCUM_HPP
#include "accum1.hpp"
#include <iostream>
int main()
{
int num[]={1,2,3,4,5};
…
accum(&num[0], &num[5])
[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 .
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])
// 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).
// traits/accum2.hpp
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits2.hpp"
#endif // ACCUM_HPP
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 .
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:
// 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;
};
…
// traits/accum3.hpp
#ifndef ACCUM_HPP
#define ACCUM_HPP
#include "accumtraits3.hpp"
#endif // ACCUM_HPP
…
template<>
class AccumulationTraits<float> {
public:
typedef double AccT;
static double const zero = 0.0; // ERROR: not an integral type
};
…
template<>
class AccumulationTraits<float> {
public:
typedef double AccT;
static double const zero;
};
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;
}
};
…
[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
// 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
// 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};
[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 .
• 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 ).
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 .
// traits/sumpolicy2.hpp
#ifndef SUMPOLICY_HPP
#define SUMPOLICY_HPP
#endif // SUMPOLICY_HPP
// 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<>
class SumPolicy<false> {
public:
template<typename T1, typename T2>
static void accumulate (T1& total, T2 const & value) {
total = total + value;
}
};
#endif // SUMPOLICY_HPP
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 .
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>
#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;
};
}
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>
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.
// traits/elementtype.cpp
#include <vector>
#include <list>
#include <stack>
#include <iostream>
#include <typeinfo>
int main()
{
std::stack<bool> s;
print_element_type(s);
}
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 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.
// 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 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;
int main()
{
std::cout << "int: ";
check<int>();
int: !IsClassT
MyClass: IsClassT
MyStruct: IsClassT
MyUnion: IsClassT
enum: !IsClassT
myfunc(): !IsClassT
// traits/apply1.hpp
// traits/apply1.cpp
#include <iostream>
#include "apply1.hpp"
int main()
{
intx=7;
apply (x, print);
apply (x, incr);
}
T h e call
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
[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.
// traits/typeop1.hpp
// traits/typeop2.hpp
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
// 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;
};
template<typename T>
Array<T> operator+ (Array<T> const&, Array<T> 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:
// traits/ifthenelse.hpp
#ifndef IFTHENELSE_HPP
#define IFTHENELSE_HPP
#endif // IFTHENELSE_HPP
// traits/promote2.hpp
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; \
};
// traits/promote4.hpp
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 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 ]
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
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 .
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.
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;
};
// 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"
int main()
{
MyClass1 mc1;
MyClass2 mc2;
foo<MyClass1,MyClass2>(mc1,mc2);
}
// traits/rparam2.cpp
#include "rparam.hpp"
#include "rparamcls.hpp"
int main()
{
MyClass1 mc1;
MyClass2 mc2;
foo(mc1,mc2); // same as foo_core<MyClass1,MyClass2>(mc1,mc2)
}
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.
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
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;
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"
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.
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.
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
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 :
[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 ).
A s annou nced earli er, we' re collecti ng th e defau lts i n a bas e clas s :
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 :
PolicySelector<Policy3_is<CustomPolicy>,
DefaultPolicyArgs,
DefaultPolicyArgs,
DefaultPolicyArgs>
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.
// inherit/empty.cpp
#include <iostream>
class EmptyClass {
};
int main()
{
std::cout << "sizeof(EmptyClass): " << sizeof(EmptyClass)
<< '\n';
}
ZeroSizedT z[10];
…
&z[i] - &z[j] // compute distance between pointers/addresses
// inherit/ebco1.cpp
#include <iostream>
class Empty {
typedef int Int; // typedef members don't make a class nonempty
};
#include <iostream>
class Empty {
typedef int Int; // typedef members don't make a class nonempty
};
int main()
{
std::cout << "sizeof(Empty): " << sizeof(Empty) << '\n';
std::cout << "sizeof(EmptyToo): " << sizeof(EmptyToo) << '\n';
std::cout << "sizeof(NonEmpty): " << sizeof(NonEmpty) << '\n';
}
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.
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>.
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
// inherit/basememberpair.hpp
#ifndef BASE_MEMBER_PAIR_HPP
#define BASE_MEMBER_PAIR_HPP
#endif // BASE_MEMBER_PAIR_HPP
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:
// inherit/objectcounter.hpp
#include <stddef.h>
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;
}
};
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>
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;
}
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() {
}
};
int main()
{
Base<NotVirtual>* p1 = new Derived<NotVirtual>;
p1->foo(); // calls Base::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
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 .
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
// meta/pow3.hpp
#ifndef POW3_HPP
#define POW3_HPP
#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
template<int N>
class Pow3 {
public:
enum { result = 3 * Pow3<N-1>::result };
};
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 };
};
// meta/pow3.cpp
#include <iostream>
#include "pow3.hpp"
int main()
{
std::cout << "Pow3<7>::result = " << Pow3<7>::result
<< '\n';
}
3 * Pow3<6>::result
struct TrueConstants {
enum { Three = 3 };
static int const Four = 4;
};
// meta/pow3b.hpp
#ifndef POW3_HPP
#define POW3_HPP
#endif // POW3_HPP
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
#endif // SQRT_HPP
// 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
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
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
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
result = 4
(16<=8*8) ? Sqrt<16,1,8>::result
: Sqrt<16,9,16>::result
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"
// meta/ifthenelse.hpp
#ifndef IFTHENELSE_HPP
#define IFTHENELSE_HPP
public:
typedef Ta ResultT;
};
#endif // IFTHENELSE_HPP
int I;
for (I=1; I*I<N; ++I) {
;
}
// I now contains the square root of N
// meta/sqrt3.hpp
#ifndef SQRT_HPP
#define SQRT_HPP
#endif // SQRT_HPP
• 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
// meta/sqrt4.hpp
#ifndef SQRT_HPP
#define SQRT_HPP
#include "ifthenelse.hpp"
#endif // SQRT_HPP
Sqrt<16>::result = 4
Sqrt<25>::result = 5
Sqrt<42>::result = 7
Sqrt<1>::result = 1
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;
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> > >
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
// meta/loop1.hpp
#ifndef LOOP1_HPP
#define LOOP1_HPP
#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 };
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
w o u l d be a l o t be tte r.
// 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);
}
};
// 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
// meta/loop2.cpp
#include <iostream>
#include "loop2.hpp"
int main()
{
int a[3] = { 1, 2, 3};
int b[3] = { 5, 6, 7};
Inste ad o f w ri ti ng
dot_product(3,a,b)
w e w ri te
dot_product<3>(a,b)
DotProduct<3,int>::result(a,b)
T h u s, f o r
dot_product<3>(a,b)
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)
[ 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
// meta/unruh.cpp
template<>
class is_prime<0,0> {
public:
enum {prim=1};
};
template<>
class is_prime<0,1> {
public:
enum {prim=1};
};
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();
}
// 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);
}
// 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;
}
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
// exprtmpl/sarray1.cpp
#include "sarray1.hpp"
#include "sarrayops1.hpp"
int main()
{
SArray<double> x(1000), y(1000);
…
x = 1.2*x + x*y;
}
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 ) .
// 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;
}
• 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 .
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];
}
}
F o r o u r e x am pl e e x pre ssi o n
1.2*x + x*y;
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 :
// exprtmpl/exprops1.hpp
#include <stddef.h>
#include <cassert>
public:
// constructor initializes references to operands
A_Add (OP1 const& a, OP2 const& b)
: op1(a), op2(b) {
}
public:
// constructor initializes references to operands
A_Mult (OP1 const& a, OP2 const& b)
: op1(a), op2(b) {
}
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
public:
// constructor initializes value
A_Scalar (T const& v)
: s(v) {
}
// exprtmpl/exprops1a.hpp
// 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
};
[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.
// exprtmpl/exprarray.hpp
#include <stddef.h>
#include <cassert>
#include "sarray1.hpp"
public:
// create array with initial size
explicit Array (size_t s)
: expr_rep(s) {
}
// exprtmpl/exprops2.hpp
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 :
A_Mult<T,A_Scalar<T>,R2>(A_Scalar<T>(s), b.rep())
and w rap ag ai n:
18.2.4 Review
int main()
{
Array<double> x(1000), y(1000);
…
x = 1.2*x + x*y;
}
1.2*x + x*y
and R2 i s su bsti tu te d w i th
Array<double,
A_Add<double,
A_Mult<double, A_Scalar<double>, SArray<double> >,
A_Mult<double, SArray<double>, SArray<double>>>>
A_Add<double,
A_Mult<double, A_Scalar<double>, SArray<double> >,
A_Mult<double, SArray<double>, SArray<double> > > >
(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.
x[y] = 2*x[y];
sh o u l d m e an th e sam e as
// exprtmpl/exprops3.hpp
private:
A1 const & a1; // reference to first operand
A2 const & a2; // reference to second operand
};
// exprtmpl/exprops4.hpp
x = A*x;
x = A*y;
template<typename T>
class CopierInterface {
public:
virtual void copy_to(Array<T, SArray<T> >&) const;
};
template<typename R>
double foo(Array<double, R> const&);
[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
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:
if (TypeT<T>::IsPtrT) {
…
}
else if (TypeT<T>::IsClassT) {
…
}
// types/type1.hpp
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
MK_FUNDA_TYPE(bool)
e x pands to th e f o l l o w i ng :
// types/type1test.cpp
#include <iostream>
#include "type1.hpp"
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
// 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).
// 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;
};
// types/type4.hpp
#include <stddef.h>
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;
};
// 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 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 };
};
…
// 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 };
};
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;
};
template<class T>
struct X {
long aligner;
Tm;
};
struct X0 {
long aligner;
};
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
template<typename T,
bool convert_possible = !CompoundT<T>::IsFuncT &&
!CompoundT<T>::IsArrayT>
class ConsumeUDC {
public:
operator T() const;
};
char enum_check(bool);
char enum_check(char);
char enum_check(signed char);
char enum_check(unsigned char);
char enum_check(wchar_t);
[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 .
// 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
// types/typet.hpp
#ifndef TYPET_HPP
#define TYPET_HPP
// define IsFundaT<>
#include "type1.hpp"
// define IsEnumT<>
#include "type7.hpp"
// define IsClassT<>
#include "type8.hpp"
#endif // TYPET_HPP
// types/types.cpp
#include "typet.hpp"
#include <iostream>
class MyClass {
};
void myfunc()
{
}
enum E { e1 };
int main()
{
std::cout << "int:" << std::endl;
check<int>();
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
void do_something()
{
Something* ptr = new Something;
delete ptr;
}
void do_something()
{
Something* ptr = 0;
try {
ptr = new Something;
void do_two_things()
{
Something* first = new Something;
first->perform();
delete second;
delete first;
}
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;
}
20.1.2 Holders
// pointers/holder.hpp
public:
// default constructor: let the holder refer to nothing
Holder() : ptr(0) {
}
// pointer operators
T& operator* () const {
return *ptr;
}
T* operator-> () const {
return ptr;
}
private:
// no copying and copy assignment allowed
Holder (Holder<T> const&);
Holder<T>& operator= (Holder<T> const&);
};
void do_two_things()
{
Holder<Something> first(new Something);
first->perform();
X x;
Y y(x); // explicit conversion
and
X x;
Y y = x; // implicit conversion
// 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;
}
…
};
// 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)
…
};
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());
…
}
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 .
Something* load_something()
{
Holder<Something> result(new Something);
read_something(result.get_pointer());
read_something(&*result);
read_something(result.operator->());
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:
No te ag ai n th at th e sy ntax
Holder<X> h = p;
MyClass x;
Something* creator()
{
Holder<Something> h(new Something);
MyClass x; // for illustration purposes
return h.release();
}
20.1.8 Trules
// pointers/trule.hpp
#ifndef TRULE_HPP
#define TRULE_HPP
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
// pointers/holder2extr.hpp
public:
Holder (Trule<T> const& t) {
ptr = t.ptr;
const_cast<Trule<T>&>(t).ptr = 0;
}
// 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());
…
}
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 .
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&);
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&);
// pointers/stdobjpolicy.hpp
class StandardObjectPolicy {
public:
template<typename T> void dispose (T* object) {
delete object;
}
};
// 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 .
// 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;
public:
// default constructor (no explicit initialization):
CountingPtr() {
this->object_pointed_to = NULL;
}
// 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)
}
private:
// helpers:
// - init with ordinary pointer (if any)
void init (T* p) {
if (p != NULL) {
CounterPolicy::init(p);
}
this->object_pointed_to = p;
}
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 .
// pointers/simplerefcount.hpp
class SimpleReferenceCount {
private:
size_t* counter; // the allocated counter
public:
SimpleReferenceCount () {
counter = NULL;
}
public:
// allocate the counter and initialize its value to one:
template<typename T> void init (T*) {
counter = alloc_counter();
*counter = 1;
}
// increment by one:
template<typename T> void increment (T*) {
++*counter;
}
// decrement by one:
template<typename T> void decrement (T*) {
--*counter;
}
// pointers/memberrefcount.hpp
// increment by one:
void increment (ObjectT* object) {
++object->*CountP;
}
// decrement by one:
void decrement (ObjectT* object) {
--object->*CountP;
}
class ManagedType {
private:
size_t ref_count;
public:
typedef CountingPtr<ManagedType,
MemberReferenceCount
<ManagedType,
size_t,
&ManagedType::ref_count> >
Ptr;
…
};
20.2.7 Constness
• 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 )
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 T,
typename CounterPolicy = SimpleReferenceCount,
typename ObjectPolicy = StandardObjectPolicy>
class CountingPtr : private CounterPolicy, private ObjectPolicy {
…
public:
operator bool() const {
return this->object_pointed_to != (T*)0;
}
};
if (cp) …
o r
while (!cp) …
[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.
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;
}
…
};
20.2.9 Comparisons
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;
}
};
[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.
[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
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:
// 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 ).
Duo<bool,int> result;
result.v1 = true;
result.v2 = 42;
return result;
w e can w ri te
return make_duo(true,42);
return Duo<bool,int>(true,42);
// 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.
// tuples/duo1.hpp
#ifndef DUO_HPP
#define DUO_HPP
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) {
}
// field access
T1& v1() {
return value1;
}
T1 const& v1() const {
return value1;
}
T2& v2() {
return value2;
}
T2 const& v2() const {
return value2;
}
};
#endif // DUO_HPP
W e m ade th e f o l l o w i ng ch ang e s:
// tuples/duo1.cpp
#include "duo1.hpp"
Duo<float,int> foo ()
{
return make_duo(42,42);
}
int main()
{
if (foo() == make_duo(42,42.0)) {
…
}
}
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:
// tuples/duo2.hpp
private:
T1 value1; // value of first field
T2 value2; // value of second field
public:
// the other public members are unchanged
…
};
// tuples/duo6.hpp
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 {
}
…
};
q4.v2().v1()
// tuples/duo5.hpp
#include "typeop.hpp"
// tuples/duo4.hpp
#include "typeop.hpp"
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;
val<1>(t) = true;
val<2>(t) = 42;
val<3>(t) = 0.2;
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()
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 ):
// 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)) {
}
};
[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 .
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 .
[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 ).
// 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;
val<1>(t3) = true;
val<2>(t3) = 42;
val<3>(t3) = 0.2;
Tuple<bool,int,float> t3;
f();
[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 .
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.
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.
int foo'()
{
int param = 0;
int answer = 0;
answer = ++(int&)param;
return answer + param;
}
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
[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.
int ia[10];
// 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 type of pf
std::cout << "Types of pf: " << typeid(pf).name()
<< '\n';
// print type of rf
std::cout << "Types of rf: " << typeid(rf).name()
<< '\n';
}
foo() called
Types of foo: void ()
Types of FooT: void ()
foo() called
foo() called
Types of pf: FooT *
foo() called
Types of rf: void ()
class B1 {
private:
int b1;
public:
void mf1();
};
void B1::mf1()
{
std::cout << "b1="<<b1<<std::endl;
}
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;
}
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.
int main()
{
D obj;
obj.mf1();
obj.mf2();
}
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.
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
(*ptr)()
ptr()
[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
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>
// ''function call''
int operator() () const {
return value;
}
};
int main()
{
ConstantIntFunctor seven(7);
ConstantIntFunctor fortytwo(42);
client(seven);
client(fortytwo);
}
#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
…
}
}
[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;
}
};
}
class RuntimeCmp {
…
};
class MyCriterion {
public:
bool operator() (SomeType const&, SomeType const&) const;
};
class MyCriterion {
public:
virtual bool operator() (SomeType const&,
SomeType const&) const = 0;
};
template<MyCriterion& F>
void sort (… );
LessThan order;
class CriterionWrapper {
public:
bool operator() (… ) {
return wrapped_function(… );
}
};
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>
// 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>
initialize<FunctionReturningIntWrapper<std::rand> >(v);
[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.
class SuperFunc {
public:
void operator() (int, char**);
};
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
…
}
};
[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.
// functors/functorparam1.hpp
#include "ifthenelse.hpp"
// 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
// functors/functionptrt.hpp
// 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
// functors/functionptr.hpp
#include "forwardparam.hpp"
#include "functionptrt.hpp"
// 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);
}
};
// functors/funcptr.hpp
#include "functionptr.hpp"
// functors/functordemo.cpp
#include <iostream>
#include <string>
#include <typeinfo>
#include "funcptr.hpp"
double seven()
{
return 7.0;
}
std::string more()
{
return std::string("more");
}
int main()
{
demo(func_ptr(seven));
demo(func_ptr(more));
}
22.7 Function Object Composition
// 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);
}
};
class AbsSine {
public:
double operator() (double a) {
return std::abs(std::sin(a));
}
};
// 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) {
}
// 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";
// functors/composeconv.hpp
// 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";
w e can no w u se th e m o re co nci se
compose(Abs(), Sine())
// functors/compose3.hpp
// functors/compose4.hpp
#include "forwardparam.hpp"
// 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);
}
};
// functors/math3.hpp
#include <cmath>
#include <cstdlib>
// ''function call'':
T operator() (T v) const {
return std::abs(v);
}
};
// ''function call'':
T operator() (T a) const {
return std::sin(a);
}
};
// 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";
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.
[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.
// functors/compose6.cpp
#include <iostream>
#include "funcptr.hpp"
#include "compose6.hpp"
#include "composeconv.hpp"
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';
}
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
// functors/clamp.hpp
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 .
…
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?
}
// functors/boundval.hpp
#include "typeop.hpp"
// functors/binder1.hpp
// functors/binderparams.hpp
#include "ifthenelse.hpp"
// functors/binder2.hpp
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 .
// functors/binder3.hpp
// functors/signselect.hpp
#include "ifthenelse.hpp"
// functors/binder4.hpp
// functors/binder5.hpp
#include "ifthenelse.hpp"
#include "boundval.hpp"
#include "forwardparam.hpp"
#include "functorparam.hpp"
#include "binderparams.hpp"
#include "signselect.hpp"
// 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;
// functors/bindconv.hpp
#include "forwardparam.hpp"
#include "functorparam.hpp"
// functors/bindtest.cpp
#include <string>
#include <iostream>
#include "funcptr.hpp"
#include "binder5.hpp"
#include "bindconv.hpp"
int main()
{
bool result = bind<1>(func_ptr(func), "Comparing")(1.0, 2.0);
std::cout << "bound function returned " << result << '\n';
}
// functors/bindfp2.hpp
// functors/functorops.cpp
#include <iostream>
#include <string>
#include <typeinfo>
#include "functorops.hpp"
// 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);
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
// functors/functorops.hpp
#ifndef FUNCTOROPS_HPP
#define FUNCTOROPS_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"
#endif // FUNCTOROPS_HPP
22.10 Afternotes
// 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();
}
[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 .
[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)
// 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();
}
#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);
}
C + + :
// File guard_demo.hpp:
#ifndef GUARD_DEMO_HPP
#define GUARD_DEMO_HPP
…
#endif // GUARD_DEMO_HPP
int main()
{
not_so_fast();
}
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.
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;
}
[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.
// Translation unit 1:
void unused(int = 3);
int main()
{
}
// Translation unit 2:
void unused(int = 4);
// Translation unit 1:
class X {
public:
X(int);
X(int, int);
};
X::X(int = 0)
{
}
class D : public X {
};
// Translation unit 2:
class X {
public:
X(int);
X(int, int);
};
X::X(int = 0, int = 0)
{
}
// File header.hpp:
#ifndef HEADER_HPP
#define HEADER_HPP
class MiniBuffer {
char buf[length];
...
};
#endif // HEADER_HPP
// File header.hpp:
#ifndef HEADER_HPP
#define HEADER_HPP
void init();
#endif // HEADER_HPP
// File tmpl_def.cpp:
#include "header.hpp"
// File init.cpp:
#include "header.hpp"
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)
}
int main()
{
display_num(399); // matches (1) better than (2)
display_num(3.99); // matches (2) better than (1)
}
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 .
• 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.
int main()
{
combine (1, 2); // ambiguous!
}
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)
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
}
#include <stddef.h>
class BadString {
public:
BadString(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.
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.
class Wonder {
public:
void tick(); // (1)
void tick() const; // (2)
void tack() const; // (3)
};
T o su m m ari z e :
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.
class Base {
public:
operator short() const;
};
void count(int);
void process(Derived const& object)
{
count(object); // matches with user-defined conversion
}
void count(short);
• 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
class Interface {
…
};
[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.
class IndirectFunctor {
public:
…
operator()(double, double);
operator FuncType*() const;
};
void compute()
{
…
int (*funcPtr)(Vector const&) = n_elements; // selects (2)
…
}
#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;
}
• T u to ri al l e v e l C + + (u nm o de rate d)
•
alt.comp.lang.learn.c-c++
[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 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
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 g le brack e t h ack
an g le brack e ts
A N S I
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
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 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.
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
C R T P
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
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
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
f u n cto 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
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
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
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
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
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
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 .
S e e al so [e x p li ci t sp e ci ali z ati o n ]
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 .
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
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
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
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
S e e al so [class te m p late ]
te m p late arg u m e n t
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
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