Sie sind auf Seite 1von 7

12/3/2016

Variadicmacrostricks|Codecraft

Codecraft
software=science+art+people

Variadicmacrostricks
Haveyoueverwantedtowriteaforeachloopoveralltheargsofa
variadicmacro?Orhaveyoueverwantedtooverloadamacroonthe
numberofarguments?(Ifyouresayingtoyourself,goodgrief,why?
Illdescribeausecaseattheboomofthispost.)
Ilearnedhowtodothistoday,andIwantedtoblogaboutittocement
thetechniqueinmyownmind.

(hp://xkcd.com/1319/)
WhathappenedwhenIdecidedtolearnthistechnique.Imtryingto
spareyou:)Imagecredit:xkcd.com
https://codecraft.co/2014/11/25/variadicmacrostricks/

1/7

12/3/2016

Variadicmacrostricks|Codecraft

Simplevariadicmacros
Therstpieceofmagicyouneedtodosomethinglikethisis
__VA_ARGS__.Thisallowsyoutowritemacrosthattakeanarbitrary
numberofarguments,using...torepresentthemacrosparameters:
1 #deneeprintf(fmt,...)\
2 fprintf(stderr,fmt,__VA_ARGS__)
viewrawvariadic_macro_1hostedwith byGitHub
Nice.__VA_ARGS__isastandardfeatureofC99,andIveknownaboutit
foralongtime.IvealsoknownaboutGCC(andClangs)extension,
whichaachesspecialmeaningto##__VA_ARGS__ifitsprecededbya
commaitremovesthecommaif##__VA_ARGS__expandstonothing.IfI
changemymacrodenitionto:
1 #deneeprintf(fmt,...)\
2 fprintf(stderr,fmt,##__VA_ARGS)
viewrawfancier_variadic_macrohostedwith

byGitHub

Icannowcalleprintf("hello,world");withoutacomplaintfrom
thecompiler.

Butitsnotenough
Thatdoesntletmedoaforeachloop,though.AlltheargsthatIpass
areexpanded,butIcantdoanythingwiththem,individually.Ihaveno
namesformymacrosparametersjusttheanonymous.
Iwentpokingaround,notexpectingtondasolution,butIwas
pleasantlysurprised.

Thepaired,slidingarglisttrick
Thenextbuildingblockweneedisatechniquethatusestwo
complementarymacrosplus__VA_ARGS__toselectsomethingspecic
outofamacroarglistofunknownsize.Ifounditinanansweron
stackoverow.com(hp://stackoverow.com/a/11763277),andyoucan
parseitalloutdirectlyfromthere,butthemagicsalileopaque.Heres
anexplanationthattakesitonestepatatime:
https://codecraft.co/2014/11/25/variadicmacrostricks/

2/7

12/3/2016

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Variadicmacrostricks|Codecraft

//Acceptanynumberofargs>=N,butexpandtojusttheNthone.Inthiscase,
//wehaveseledon5asN.Wecouldpickadierentnumberbyadjusting
//thecountofthrowawayargsbeforeN.Notethatthismacroisprecededby
//anunderscoreitsanimplementationdetail,notsomethingweexpectpeople
//tocalldirectly.
#dene_GET_NTH_ARG(_1,_2,_3,_4,N,...)N
//Counthowmanyargsareinavariadicmacro.OnlyworksforuptoN1args.
#deneCOUNT_VARARGS(...)_GET_NTH_ARG(__VA_ARGS__,4,3,2,1)
intmain(){
printf(onearg:%d\n,COUNT_VARARGS(1));
printf(threeargs:%d\n,COUNT_VARARGS(1,2,3));
}

//output
onearg:1
threeargs:3

viewrawpaired_sliding_arg_list_macro_trick_1hostedwith
GitHub

by

Seehowitworks?Therstmacro,_GET_NTH_ARG(),takesanynumber
ofargs>=N,butalwaysreturnsitemN(inthiscase,N=5).Thesecond
macro,COUNT_VARARGS(...),takesanarbitrarynumberofargs<N,
padswithcandidatevaluesitwantstoextract,andusesitsargstocall
_GET_NTH_ARG()inawaythatputstherightcandidatevalueinthe
knownNposition.Inthiscase,themeaningfulpieceofinfothatwewant
inpositionNisanargcount;weveprovidedthevalues4,3,2,1as
candidatevalues,andoneofthosevalueswillbeinpositionNon
expansion.
TweakingthismacropairtohandleadierentNisamaerofadjusting
whatcomesbeforeNintherstmacro,andwhatcomesafter
__VA_ARGS__inthesecondmacro.Illleavethatasanexerciseforthe
reader.:)
Wedonthavetoselectanumericcountwiththistechnique;wecould
useittoselectargnameswiththe#operator,orevenothermacros.This
willcomeinhandyinamoment.Butrst,letsaddressoneshortcoming:
COUNT_VARARGS(...)doesnthandlethecaseofzeroargs.Heresthe
x:
1
2
3

//Acceptanynumberofargs>=N,butexpandtojusttheNthone.Themacro
//thatcallsusstillonlysupports4args,butthesetofvalueswemight
//needtoreturnis1larger,soweincreaseNto6.

https://codecraft.co/2014/11/25/variadicmacrostricks/

3/7

12/3/2016

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Variadicmacrostricks|Codecraft

#dene_GET_NTH_ARG(_1,_2,_3,_4,_5,N,...)N

//Counthowmanyargsareinavariadicmacro.WenowuseGCC/Clangsextensionto
//handlethecasewhere...expandstonothing.Wemustaddaplaceholderargbefore
//##__VA_ARGS__(itsvalueistotallyirrelevant,butitsnecessarytopreserve
//theshiftingosetwewant).Inaddition,wemustadd0asavalidvaluetobein
//theNposition.
#deneCOUNT_VARARGS(...)_GET_NTH_ARG(ignored,##__VA_ARGS__,4,3,2,1,0)
intmain(){
printf(zeroargs:%d\n,COUNT_VARARGS());
printf(threeargs:%d\n,COUNT_VARARGS(1,2,3));
}
//output
zeroargs:0
threeargs:3

viewrawpaired_sliding_arg_list_macro_trick_2hostedwith
GitHub

by

Macrooverrides
Now,wecanbuildonthistodeneavariadicmacrothathasan
expansionoverriddenbyhowmanyargsitreceives.Thisiswhatthe
originalstackoverowanswerdid.Somethinglikethis:
1
2
3
4
5
6
7
8
9
10
11
12
13
14

//Denetwooverridesthatcanbeusedbytheexpansionof
//ourmainmacro.
#dene_MY_CONCAT3(a,b,c)abc
#dene_MY_CONCAT2(a,b)ab
//Deneamacrothatusesthepaired,slidingarglist
//techniquetoselecttheappropriateoverride.Youshould
//recognizethisassimilartotheGET_NTH_ARG()macroin
//previousexamples.
#dene_GET_OVERRIDE(_1,_2,_3,NAME,...)NAME
//Deneamacrothatconcatseither3or2stringstogether.
#deneMY_CONCAT(...)_GET_OVERRIDE(__VA_ARGS__,\
_MY_CONCAT3,_MY_CONCAT2)(__VA_ARGS__)

https://codecraft.co/2014/11/25/variadicmacrostricks/

4/7

12/3/2016

Variadicmacrostricks|Codecraft

15
16 intmain(){
17 printf(3args:%s\n,MY_CONCAT(a,b,c));
18 printf(2args:%s,MY_CONCAT(a,b));
19 }
20
21 //output
22 3args:abc
23 2args:ab
viewrawmacros_overridden_by_arg_counthostedwith byGitHub
Nowweregeingclosetobeingabletocodeaforeachloopoverall
theargstoavariadicmacro.Ifthemacrothatgetsoverriddenhasafor
eachavor,itallcomestogether:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

//Acceptanynumberofargs>=N,butexpandtojusttheNthone.
//Here,N==6.
#dene_GET_NTH_ARG(_1,_2,_3,_4,_5,N,...)N
//Denesomemacrostohelpuscreateoverridesbasedonthe
//arityofaforeachstylemacro.
#dene_fe_0(_call,...)
#dene_fe_1(_call,x)_call(x)
#dene_fe_2(_call,x,...)_call(x)_fe_1(_call,__VA_ARGS__)
#dene_fe_3(_call,x,...)_call(x)_fe_2(_call,__VA_ARGS__)
#dene_fe_4(_call,x,...)_call(x)_fe_3(_call,__VA_ARGS__)
/**
*Provideaforeachconstructforvariadicmacros.Supportsup
*to4args.
*
*Exampleusage1:
*#deneFWD_DECLARE_CLASS(cls)classcls;
*CALL_MACRO_X_FOR_EACH(FWD_DECLARE_CLASS,Foo,Bar)
*
*Exampleusage2:
*#deneSTART_NS(ns)namespacens{
*#deneEND_NS(ns)}
*#deneMY_NAMESPACESSystem,Net,Hp
*CALL_MACRO_X_FOR_EACH(START_NS,MY_NAMESPACES)
*typedeffooint;
*CALL_MACRO_X_FOR_EACH(END_NS,MY_NAMESPACES)
*/

https://codecraft.co/2014/11/25/variadicmacrostricks/

5/7

12/3/2016

29
30
31

Variadicmacrostricks|Codecraft

#deneCALL_MACRO_X_FOR_EACH(x,...)\
_GET_NTH_ARG(ignored,##__VA_ARGS__,\
_fe_4,_fe_3,_fe_2,_fe_1,_fe_0)(x,##__VA_ARGS__)

viewrawfor_each_macrohostedwith

byGitHub

Okay,butwhy?
IsaidIdprovidesomeexplanationofwhythistechniquecouldbe
useful.Ingeneral,Iamnotafanofmacrosrewritingthesyntaxofa
programminglanguage;thatcanobscurewhatsreallyhappening,and
makeforasteeperlearningcurve.
Ontheotherhand,sometimestheyarereallyhelpful.Theycanmake
codemuchlessverbose/repetitivebyeliminatingnoiseandboilerplate.
Occasionally,Irunintocaseswherethattradeoseemsworthittome.
Moreimportantly,macroshaveapropertythatyoucantgetanyother
waythesamefragmentofcodecanhavemultiplemeanings,andcan
maintainthissemanticparallelismwithoutbeingsusceptibletohuman
memoryerrors,laziness,ormisunderstanding.Ihavepreviously
bloggedabouthowvaluablethiscanbeineliminatingencapuslation
problemswithenums(hps://codecraft.co/2012/10/29/howenums
spreaddiseaseandhowtocureit/),butIrecentlyfoundanotherneed
forit.Inmyprojecttocreateanewprogramminglanguage
(hps://codecraft.co/2013/10/24/onbreadrecipesmapsandintentions/),
Ihavetocreatesomefoundationpackagesandclassestheanalogto
java.langinjava,orSystemandMyin.NET.Thisfoundationneedsto
wrieninC/C++toavoidachickenandeggproblem.ThatmeansIneed
somewaytousenamespaces,classes,andotherC++constructsinthe
sourcecode,butalsogeneratepackageandclassconstructsvisibletomy
intentcompiler.Macroswereanobviousanswer.
Theonlyproblemwasthatsomeofmymacrosneededtobevariadic
andIneededforeachstylesemantics.Hencemyresearch.:)
Howaboutyou?Haveyoueverhadaneedforsomethinglikethis?
TUE,NOV25,2014
DANIELHARDMAN

MACROS,NAMESPACES,TRICKS,VARIADIC,__VA_ARGS__

2thoughtsonVariadicmacrostricks
https://codecraft.co/2014/11/25/variadicmacrostricks/
1.
JasonIveysays:

6/7

12/3/2016

Variadicmacrostricks|Codecraft

1.

JasonIveysays:
Ilovethepreprocessorforexactlythiskindofwork.Although
macrosgetabadnamethesedays,thepreprocessoritselfisstilla
powerfulandwonderfultoolwhenusedfortheproblemsyou
described.
WhatIvediscoveredrecentlyasIhavebeenwritingcustommacros
isthatmany,ifnotall,oftheunderlyingcodeIinventisalready
wrienintheboost.preprocessorlibrary.Imnotsureifithasan
identicalsolutiontowhatyouhavecreatedabovebutIknowithasa
macrotoconvertthevar_argstoacountandlist.
(BOOST_PP_VARIADIC_TO_LIST)
Iwasalsopleasedtodiscoverthattheyhavethemechanicstoquickly
implementmyfavoritepreprocessorpaernyoutaughtmeyears
ago,theenumdeclarationviaincludele.(BOOST_PP_ITERATION)
Inmyopinion,theboost.preprocessorlibrarydocumentationleavesa
liletobedesiredintermsofexamplesanddescriptions.Butthereis
alottheretoworkwith.
REPLY MON,JAN5,2015AT6:23PM
DanielHardmansays:
Jason:Iverunintoboost.preprocessorafewtimes,butIhavent
useditmuch.Shameonme!Thanksforremindingmetolearn
aboutit.
WhenIrunintoaprogrammingproblemthatIdontknowhow
tosolve,Ioftenliketowritemyownsolutionnotsomuch
becauseIwantto*use*myownsolution,asbecauseIwantto
learnwhatittakestosolvetheproblem.OnceIvesolvedittomy
ownsatisfaction(and,sometimes,wrienaboutitsoIunderstand
howitworkswell),thenIcanappreciateamoreelegantor
generalsolution,andchuckmyown.Illhavetolookinto
boost.preprocessortoseeifitsolvestheproblemIwasseeingin
theintentcodebase;ifso,Illgladlyswitchover,sinceImalready
usingboostafairamount.
REPLY MON,JAN5,2015AT6:57PM

BLOGATWORDPRESS.COM.

https://codecraft.co/2014/11/25/variadicmacrostricks/

7/7

Das könnte Ihnen auch gefallen