Tải bản đầy đủ - 0 (trang)
Chapter 65.  Customize intentionally and explicitly

Chapter 65.  Customize intentionally and explicitly

Tải bản đầy đủ - 0trang

Summary

Intentionalisbetterthanaccidental,andexplicitisbetterthan

implicit:Whenwritingatemplate,providepointsof

customizationknowinglyandcorrectly,anddocumentthem

clearly.Whenusingatemplate,knowhowthetemplateintends

foryoutocustomizeitforusewithyourtype,andcustomizeit

appropriately.



Discussion

Acommonpitfallwhenwritingtemplatelibrariesisproviding

unintentionalpointsofcustomizationthatis,pointswherea

caller'scodecangetlookedupandusedinsideyourtemplate,

butyoudidn'tmeanforacaller'scodetogetinvolved.It'seasy

todo:Justcallanotherfunctionoroperatorthenormalway

(unqualified),andifoneofitsargumentshappenstobeofa

templateparametertype(orarelatedtype)thenADLwillpick

itup.Examplesabound:SeeItem58foranexample.

Instead,beintentional:Knowthethreemajorwaystoprovide

pointsofcustomizationinatemplate,decidewhichoneyou

wanttouseatagivenpointinyourtemplate,andcodeit

correctly.Then,checktoverifythatthatyoudidn'taccidentally

alsocodeacustomizationhookinplaceswhereyoudidn'tmean

to.

Thefirstwaytoprovideapointofcustomizationistheusual

"implicitinterface"(seeItem64)approachwhereyourtemplate

simplyreliesonatype'shavinganappropriatememberwitha

givenname:



//Option1:ProvideapointofcustomizationbyrequiringTto

//asamemberfunctionwithagivenname,signature,andseman



template

voidSample1(Tt){

t.foo();//fooisapointofcustomization

typenameT::value_typex;//anotherexample:providingapoin

}//izationtolookupatype(usua



ToimplementOption1,theauthorofSample1must:



Callthefunctionwithmembernotation:Justusethenatural

membersyntax.

Documentthepointofcustomization:Thetypemust

provideanaccessiblememberfunctionfoothatcanbe

calledwithgivenarguments(here,none).

Thesecondoptionistousethe"implicitinterface"method,but

withanonmemberfunctionthatislookedupviaargumentdependentlookup(i.e.,itisexpectedtobeinthenamespaceof

thetypewithwhichthetemplateisinstantiated);thisisa

majormotivationforthelanguage'sADLfeature(seeItem57).

Yourtemplateisrelyingonatype'shavinganappropriate

nonmemberwithagivenname:



//Option2:ProvideapointofcustomizationbyrequiringTto

//asanonmemberfunction,typicallylookedupbyADL,witha

//andsemantics.(Thisistheonlyoptionthatdoesn'talsowo

template

voidSample2(Tt){

foo(t);//fooisapointofcustomization



cout<
}//tionisthesamekindofpointofc



ToimplementOption2,theauthorofSample2must:

Callthefunctionwithunqualifiednonmembernotation

(includingnaturaloperatornotationinthecaseof

operators)andensurethetemplateitselfdoesn'thavea

memberfunctionwiththesamename:Itisessentialforthe

templatenottoqualifythecalltofoo(e.g.,don'twrite

SomeNamespace::foo(t))ortohaveitsownmember



functionofthesamename,becauseeitherofthosewould

turnoffADLandthuspreventnamelookupfromfindingthe

functioninthenamespaceofthetypeT.

Documentthepointofcustomization:Thetypemust

provideanonmemberfunctionfoothatcanbecalledwith

givenarguments(here,none).

Options1and2havesimilaradvantagesandapplicability:The

usercanwritethecustomizationfunctiononceforhistypeina

placewhereothertemplatelibrariescouldalsopickitup,thus

avoidingwritinglotsoflittleadapters,oneforeachtemplate

library.Thecorrespondingdrawbackisthatthesemanticswould

havetobereasonablybroadlyapplicablesoastomakesense

forallthosepotentialuses.(Notethatoperatorsinparticular

fallintothiscategory;thisisanotherreasonforItem26.)

Thethirdoptionistousespecialization,sothatyourtemplateis

relyingonatype'shavingspecialized(ifnecessary)another

classtemplateyouprovide:



//Option3:ProvideapointofcustomizationbyrequiringTto

//byspecializingSampleTraits<>andprovidea(typicallystat

//givenname,signature,andsemantics.



template

voidSample3(Tt){

typenameS3Traits::foo(t);//S3Traits<>::fooisap



typenameS3Traits::value_typex;//anotherexample:provi

}//izationtolookupa



InOption3,makingtheuserwriteanadapterensuresthat

customcodeforthislibraryisisolatedinsidethislibrary.The

correspondingdrawbackisthatthiscanbecumbersome;if



severaltemplatelibrariesneedthesamecommonfunctionality,

theuserhastowritemultipleadapters,oneforeachlibrary.

Toimplementthisoption,theauthorofSample3must:

Provideadefaultclasstemplateinthetemplate'sown

namespace:Don'tuseafunctiontemplate,whichcan'tbe

partiallyspecializedandleadstooverloadsandorder

dependencies.(SeealsoItem66.)

Documentthepointofcustomization:Theusermust

specializeS3Traitsinthetemplatelibrary'snamespacefor

hisowntype,anddocumentallofS3Traits'smembers

(e.g.,foo)andtheirsemantics.

Underalloptions,alwaysclearlydocumentalsothesemantics

requiredoffoo,notablyanyessentialactions(postconditions)

foomustguarantee,andfailuresemantics(whathappens,

includinghowerrorsarereported,iftheactionsdon'tsucceed).

Ifthepointofcustomizationmustbecustomizablealsofor

built-intypes,useOption2orOption3.

PreferOption1orOption2forcommonoperationsthatreally

areservicesprovidedbythetype.Here'salitmustest:Could

othertemplatelibrariesusethisfacilitytoo?Andarethese

generallyacceptedsemanticsforthisname?Ifso,thisoptionis

probablyappropriate.

PreferOption3forless-commonoperationswhosemeaningcan

beexpectedtovary.Youcanthenhappilymakethesame

namesmeanwhateveryouwantinanygivennamespace,

withoutconfusionorcollision.

Atemplatewithmultiplepointsofcustomizationcanchoosea

differentappropriatestrategyforeachpointofcustomization.

Thepointisthatitmustconsciouslychooseanddocument



exactlyonestrategyforeachpointofcustomization,document

therequirementsincludingexpectedpostconditionsandfailure

semantics,andimplementthechosenstrategycorrectly.

Toavoidprovidingpointsofcustomizationunintentionally:

Putanyhelperfunctionsyourtemplateusesinternallyinto

theirownnestednamespace,andcallthemwithexplicit

qualificationtodisableADL:Whenyouwanttocallyour

ownhelperfunctionandpassanobjectofthetemplate

parametertype,andthatcallshouldnotbeapointof

customization(i.e.,youalwaysintendyourhelpertobe

called,notsomeotherfunction),prefertoputthehelperin

anestednamespaceandexplicitlyturnoffADLby

qualifyingthecallorputtingthefunctionnamein

parentheses:



template

voidSample4(Tt){

S4Helpers::bar(t);//disablesADL:fooisnotapoint

(bar)(t);//alternative

}



Avoiddependingondependentnames:Informally,a

dependentnameisanamethatsomehowmentionsa

templateparameter.Manycompilersdonotsupportthe

"two-phaselookup"fordependentnamesmandatedbythe

C++Standard,andthismeansthattemplatecodethat

usesdependentnameswillbehavedifferentlyondifferent

compilersunlessittakescaretobeexplicitwhenusing

dependentnames.Particularcareisrequiredinthe

presenceofdependentbaseclasses,whichoccurwhena

classtemplateinheritsfromoneofitstemplateparameters

(e.g.,TinthecasetemplateclassC:T



{};)orfromatypethatisbuiltupfromoneofitstemplate

parameters(e.g.,Xinthecasetemplate

classC:X{};).

Inshort,whenreferringtoanymemberofadependentbase

class,alwaysexplicitlyqualifywiththebaseclassnameorwith

this->,whichyoucanthinkofjustasamagicalwayofforcing

allcompilerstodowhatyouactuallymeant:



template

classC:X{

typenameX::SomeTypes;//usebase'snestedtypeortypede

public:

voidf(){

X::baz();//callbasememberfunction

this->baz();//alternative

}

};



TheC++standardlibrarygenerallyfavorsrelyingonOption2

(e.g.,ostream_iteratorslookup

operator<<,andaccumulatelooksup

operator+,inyourtype'snamespace).Italsouses

Option3insomeplaces(e.g.,iterator_traits,

char_traits
),particularlybecausethosetraitsmustbe

specializableforbuilt-intypes.

Notethat,unfortunately,theC++standardlibraryfailsto

clearlyspecifythepointsofcustomizationofsomealgorithms.

Forexample,itclearlysaysthatthethree-parameterversionof

accumulatemustcallauser'soperator+usingOption2.Butit

doesn'tsaywhethersortmustcallauser'sswap(thereby

providinganintentionalpointofcustomizationusingOption2),

whetheritmaycallauser'sswap,orwhetheritcallsanyswap



atall;today,someimplementationsofsortdopullinauserdefinedswapwhileothersdon't.ThisItem'spointhasonlybeen

learnedrelativelyrecently,andnowthestandardscommitteeis

fixingthecurrentinadequatespecificationbyremovingsuch

fuzzinessfromthestandard.Weknowbetternow.Learnfrom

thepast.Don'tmakethesamemistakes.(Formoreoptions,

seeItem66.)



References

[Stroustrup00]Đ8.2,Đ10.3.2,Đ11.2.4[Sutter00]Đ31-34

[Sutter04d]



66.Don'tspecializefunctiontemplates

Summary

Discussion

Examples

References



Summary

Specializationisgoodonlywhenitcanbedonecorrectly:When

extendingsomeoneelse'sfunctiontemplate(including

std::swap),avoidtryingtowriteaspecialization;instead,write

anoverloadofthefunctiontemplate,andputitinthe

namespaceofthetype(s)theoverloadisdesignedtobeused

for.(SeeItem57.)Whenyouwriteyourownfunctiontemplate,

avoidencouragingdirectspecializationofthefunctiontemplate

itself.



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 65.  Customize intentionally and explicitly

Tải bản đầy đủ ngay(0 tr)

×