Beruflich Dokumente
Kultur Dokumente
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