Tải bản đầy đủ - 0 (trang)
Part III. Function Objects and Higher-Order Programming

Part III. Function Objects and Higher-Order Programming

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

Library9.Bind

HowDoestheBindLibraryImproveYourPrograms?

HowDoesBindFitwiththeStandardLibrary?

Bind

Usage

BindSummary



HowDoestheBindLibraryImproveYour

Programs?

AdaptsfunctionsandfunctionobjectsforusewithStandard

Libraryalgorithms

Consistentsyntaxforcreatingbinders

Powerfulfunctionalcomposition

WhenusingthealgorithmsfromtheStandardLibrary,youoften

needtosupplythemwithafunctionorafunctionobject.Thisis

anexcellentwayofcustomizingthebehaviorofalgorithms,but

youoftenendupwritingnewfunctionobjectsbecauseyou

don'thavethetoolsnecessaryforfunctionalcompositionand

adaptationofargumentorderorarity.AlthoughtheStandard

Librarydoesoffersomeproductivetools,suchasbind1stand

bind2nd,thisisrarelyenough.Evenwhenthefunctionality

suffices,thatoftenimpliessufferingfromawkwardsyntaxthat

obfuscatesthecodeforprogrammerswhoarenotfamiliarwith

thosetools.Whatyouneed,then,isasolutionthatbothadds

functionalityandnormalizesthesyntaxforcreatingfunction

objectson-the-fly,andthisiswhatBoost.Binddoes.

Ineffect,ageneralizedbinderisasortoflambdaexpression,

becausethroughfunctionalcompositionwecanmoreorless

constructlocal,unnamedfunctionsatthecallsite.Thereare

manycaseswherethisisdesirable,becauseitservesthree

purposesreducingtheamountofcode,makingthecodeeasier

tounderstand,andlocalizingbehavior,whichinturnimplies

moreeffectivemaintenance.NotethatthereisanotherBoost

library,Boost.Lambda,whichtakesthesepropertieseven

further.Boost.Lambdaiscoveredinthenextchapter.Why

shouldn'tyoujustskipaheadtothatlibrary?Becausemostof



thetime,Boost.Binddoeseverythingyouneedwhenitcomes

tobinding,andthelearningcurveisn'tassteep.

OneofthekeystothesuccessofBindistheuniformsyntaxfor

creatingfunctionobjectsandthefewrequirementsontypes

thataretobeusedwiththelibrary.Thedesigntakesfocus

awayfromhowtowritethecodethatworkswithyourtypes,

andsetsittowhereweareallmostinterestedhowthecode

worksandwhatitactuallydoes.Whenusingadaptorsfromthe

StandardLibrary,suchasptr_funandmem_fun_ref,codequickly

becomesunnecessarilyverbosebecausewehavetoprovide

theseadaptorsinorderfortheargumentstoadheretothe

requirementsofthealgorithms.Thisisnotthecasewith

Boost.Bind,whichusesamuchmoresophisticateddeduction

system,andastraightforwardsyntaxwhentheautomatic

deductioncannotbeapplied.TheneteffectofusingBindisthat

you'llwritelesscodethatiseasiertounderstand.



HowDoesBindFitwiththeStandardLibrary?

Conceptually,BindisageneralizationoftheexistingStandard

Libraryfunctionsbind1standbind2nd,withadditionalfunctionality

thatallowsformoresophisticatedfunctionalcomposition.It

alsoalleviatestheneedtouseadaptorsforpointerstofunctions

andpointerstoclassmembers,whichsavescodingand

potentialerrors.Boost.Bindalsocoverssomeofthepopular

extensionstotheC++StandardLibrary,suchastheSGI

extensionscompose1andcompose2,andalsotheselect1stand

select2ndfunctions.So,BinddoesfitwiththeStandardLibrary,

anditdoessoverywellindeed.Theneedforsuchfunctionality

isacknowledged,andatlastinpartaddressedbytheStandard

Library,andalsoinpopularextensionstotheSTL.Boost.Bind

hasbeenacceptedfortheupcomingLibraryTechnicalReport.



Bind

Header:"boost/bind.hpp"

TheBindlibrarycreatesfunctionobjectsthatbindtoafunction

(freefunctionormemberfunction).Ratherthansupplyingallof

theargumentstothefunctiondirectly,argumentscanbe

delayed,meaningthatabindercanbeusedtocreateafunction

objectwithchangedarity(numberofarguments)forthe

functionitbindsto,ortoreordertheargumentsanywayyou

like.

Thereturntypesoftheoverloadedversionsofthefunctionbind

areunspecifiedthatis,thereisnoguaranteeforwhatthe

signatureofareturnedfunctionobjectis.Sometimes,youneed

tostorethatobjectsomewhere,ratherthanjustpassingit

directlytoanotherfunctionwhenthisneedarises,youwantto

useBoost.Function,whichiscoveredin"Library11:Function

11."Thekeytounderstandingwhatthebind-functionsreturnis

togrokthetransformationthatistakingplace.Usingoneofthe

overloadedbindfunctionstemplateunspecified-1

bind(Ff)asanexample,thiswouldbe(quotingfromtheonline

documentation),"Afunctionobject suchthattheexpression

(v1,v2,...,vm)isequivalenttof(),implicitlyconvertedtoR."

Thus,thefunctionthatisboundisstoredinsidethebinder,and

theresultofsubsequentinvocationsonthatfunctionobject

yieldsthereturnvaluefromthefunction(ifany)thatis,the

templateparameterR.Theimplementationthatwe'recovering

heresupportsuptoninefunctionarguments.

TheimplementationofBindinvolvesanumberoffunctionsand

classes,butasusers,wedonotdirectlyuseanythingother

thantheoverloadedfunctionbind.Allbindingtakesplace

throughthebindfunction,andwecanneverdependonthetype



ofthereturnvalue.Whenusingbind,theplaceholdersfor

arguments(called_1,_2,andsoon)donotneedtobe

introducedwithausingdeclarationordirective,becausethey

resideinanunnamednamespace.Thus,thereisrarelyareason

forwritingoneofthefollowinglineswhenusingBoost.Bind.

usingboost::bind;

usingnamespaceboost;



Aswasmentionedbefore,thecurrentimplementationof

Boost.Bindsupportsnineplaceholders(_1,_2,_3,andsoforth),

andthereforealsouptoninearguments.It'sinstructivetoat

leastbrowsethroughthesynopsisforahigh-level

understandingofhowthetypedeductionisperformed,and

when/whythisdoesnotalwayswork.Parsingthesignaturesfor

memberfunctionpointersandfreefunctionstakesawhilefor

theeyetogetusedto,butit'suseful.You'llseethatthereare

overloadsforbothfreefunctionsandclassmemberfunctions.

Also,thereareoverloadsforeachdistinctnumberof

arguments.Ratherthanlistingthesynopsishere,Iencourage

youtovisitBoost.Bind'sdocumentationatwww.boost.org.



Usage

Boost.Bindoffersaconsistentsyntaxforbothfunctionsand

functionobjects,andevenforvaluesemanticsandpointer

semantics.We'llstartwithsomesimpleexamplestogetto

gripswiththeusageofvanillabindings,andthenmoveonto

functionalcompositionthroughnestedbinds.Oneofthekeysto

understandinghowtousebindistheconceptofplaceholders.

Placeholdersdenotetheargumentsthataretobesuppliedto

theresultingfunctionobject,andBoost.Bindsupportsupto

ninesucharguments.Theplaceholdersarecalled_1,_2,_3,_4,

andsoonupto_9,andyouusethemintheplaceswhereyou

wouldordinarilyaddtheargument.Asafirstexample,weshall

defineafunction,nine_arguments,whichisthencalledusingabind

expression.

#include

#include"boost/bind.hpp"

voidnine_arguments(

inti1,inti2,inti3,inti4,

inti5,inti6,inti7,inti8,inti9){

std::cout<
<
}

intmain(){

inti1=1,i2=2,i3=3,i4=4,i5=5,i6=6,i7=7,i8=8,i9=9;

(boost::bind(&nine_arguments,_9,_2,_1,_6,_3,_8,_4,_5,_7))

(i1,i2,i3,i4,i5,i6,i7,i8,i9);

}



Inthisexample,youcreateanunnamedtemporarybinderand



immediatelyinvokeitbypassingargumentstoitsfunctioncall

operator.Asyoucansee,theorderoftheplaceholdersis

scrambledthisillustratesthereorderingofarguments.Notealso

thatplaceholderscanbeusedmorethanonceinanexpression.

Theoutputofthisprogramisasfollows.

921638457



Thisshowsthattheplaceholderscorrespondtotheargument

withtheplaceholder'snumberthatis,_1issubstitutedwiththe

firstargument,_2withthesecondargument,andsoon.Next,

you'llseehowtocallmemberfunctionsofaclass.



CallingaMemberFunction

Let'stakealookatcallingmemberfunctionsusingbind.We'll

startbydoingsomethingthatalsocanbedonewiththe

StandardLibrary,inordertocompareandcontrastthatsolution

withtheoneusingBoost.Bind.Whenstoringelementsofsome

classtypeinStandardLibrarycontainers,acommonneedisto

callamemberfunctiononsomeoralloftheseelements.This

canbedoneinaloop,andisall-too-oftenimplementedthusly,

buttherearebettersolutions.Considerthefollowingsimple

class,status,whichwe'llusetoshowthattheeaseofuseand

powerofBoost.Bindisindeedtremendous.

classstatus{

std::stringname_;

boolok_;

public:

status(conststd::string&name):name_(name),ok_(true){}

voidbreak_it(){

ok_=false;



}

boolis_broken()const{

returnok_;

}

voidreport()const{

std::cout<
(ok_?"workingnominally":"terriblybroken")<<'\n';

}

};



Ifwestoreinstancesofthisclassinavector,andweneedto

callthememberfunctionreport,wemightbetemptedtodoit

asfollows.

std::vectorstatuses;

statuses.push_back(status("status1"));

statuses.push_back(status("status2"));

statuses.push_back(status("status3"));

statuses.push_back(status("status4"));

statuses[1].break_it();

statuses[2].break_it();

for(std::vector::iteratorit=statuses.begin();

it!=statuses.end();++it){

it->report();

}



Thisloopdoesthejobcorrectly,butit'sverbose,inefficient(due

tothemultiplecallstostatuses.end()),andnotasclearasusing

thealgorithmfromtheStandardLibrarythatexistsforexactly



thispurpose,for_each.Tousefor_eachtoreplacetheloop,we

needtouseanadaptorforcallingthememberfunctionreport

onthevectorelements.Inthiscase,becausetheelementsare

storedbyvalue,whatweneedistheadaptormem_fun_ref.

std::for_each(

statuses.begin(),

statuses.end(),

std::mem_fun_ref(&status::report));



Thisisacorrectandsoundwaytodoititisquiteterse,and

therecanbenodoubtastowhatthecodeisdoing.The

equivalentcodefordoingthisusingBoost.Bindfollows.[1]

[1]Itshouldbenotedthatboost::mem_fn,whichhasalsobeenacceptedfortheLibraryTechnicalReport,

wouldworkjustaswellforthecaseswheretherearenoarguments.mem_fnsupersedesstd::mem_funand

std::mem_fun_ref.



std::for_each(

statuses.begin(),

statuses.end(),

boost::bind(&status::report,_1));



Thisversionisequallyclearandunderstandable.Thisisthefirst

realuseoftheaforementionedplaceholdersoftheBindlibrary,

andwhatwe'retellingboththecompilerandthereaderofour

codeisthat_1istobesubstitutedforanactualargumentby

thefunctioninvokingthebinder.Althoughthiscodedoessavea

fewcharacterswhentyping,thereisnobigdifferencebetween

theStandardLibrarymem_fun_refandbindforthisparticularcase,

butlet'sreusethisexampleandchangethecontainertohold

pointersinstead.

std::vectorp_statuses;



p_statuses.push_back(newstatus("status1"));

p_statuses.push_back(newstatus("status2"));

p_statuses.push_back(newstatus("status3"));

p_statuses.push_back(newstatus("status4"));

p_statuses[1]->break_it();

p_statuses[2]->break_it();



WecanstilluseboththeStandardLibrary,butwecannolonger

usemem_fun_ref.Weneedhelpfromtheadaptormem_fun,whichis

consideredabitofamisnomer,butagaindoesthejobthat

needstobedone.

std::for_each(

p_statuses.begin(),

p_statuses.end(),

std::mem_fun(&status::report));



Althoughthisworkstoo,thesyntaxhaschanged,eventhough

wearetryingtodosomethingverysimilar.Itwouldbeniceif

thesyntaxwasidenticaltothefirstexample,sothatthefocus

isonwhatthecodereallydoesratherthanhowitdoesit.Using

bind,wedonotneedtobeexplicitaboutthefactthatweare

dealingwithelementsthatarepointers(thisisalreadyencoded

inthetypeofthecontainer,andredundantinformationofthis

kindistypicallyunnecessaryformodernlibraries).

std::for_each(

p_statuses.begin(),

p_statuses.end(),

boost::bind(&status::report,_1));



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

Part III. Function Objects and Higher-Order Programming

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

×