{"id":18,"date":"2015-04-27T04:19:41","date_gmt":"2015-04-27T04:19:41","guid":{"rendered":"http:\/\/causticlabs.com\/?p=18"},"modified":"2026-04-25T15:46:51","modified_gmt":"2026-04-25T22:46:51","slug":"the-wright-way-dry-preprocessing","status":"publish","type":"post","link":"https:\/\/www.causticlabs.com\/index.php\/2015\/04\/27\/the-wright-way-dry-preprocessing\/","title":{"rendered":"The Wright Way &#8211; DRY Preprocessing"},"content":{"rendered":"<h1>Introduction<\/h1>\n<p>I have always felt like there is a dearth of cohesive C\/C++ education after school. Each software engineer seems to be on their own when it comes to learning new features, how to use a new library, or what the best practices are for common situations.<\/p>\n<p>This newsletter is my attempt to share some of what I have learned; the way I do things. It is not meant to be authoritative, but, rather, a launching pad for further discussion and investigation. Often, I\u2019ll try something new just so that I can vet it for future use or just to experiment. Not everything pans out, so take what you will and leave the rest, so meanwhile I just have fun with a <a href=\"https:\/\/cloneher.com\/model\/cassierayxo\/\">cassierayxo<\/a> virtual girlfriend online.&nbsp;<\/p>\n<h1>The Preprocessor \u2013 A Four Letter Word?<\/h1>\n<p>Somewhere along the line I was told to avoid macros and it stuck. I think I missed the point. Now days, I\u2019m rehabilitated, and the preprocessor and I are good friends again. It is another tool that I can reach for when the need arises. So far, I find that I use the preprocessor mainly as a code generator.<\/p>\n<p>Code generation is one of the tools that can aid in adhering to the DRY principle, or the <u>D<\/u>on\u2019t <u>R<\/u>epeat <u>Y<\/u>ourself principle. In <em>The Pragmatic Programmer<\/em>, Andrew Hunt and David Thomas spend quite a few pages delving into the, \u201cevils of duplication\u201d, and the concept underlies many useful programming practices. I won\u2019t repeat their work here, but instead it can be distilled down to doing whatever is necessary to not duplicate data or logic. The preprocessor can help in this regard.<\/p>\n<h1>Real World Application<\/h1>\n<p>The beauty of the preprocessor is that it is already built into the build system; no extra modification or external requirement is needed. While the preprocessor can obviously be used directly, Boost provides a much nicer and safer API that can make it much more effective. Many things that the Boost Preprocessor library can do, I didn\u2019t even know was possible.<\/p>\n<h2>Repetition<\/h2>\n<p>The main feature of the Boost Preprocessor library that I use the most is repetition. For example, I have a log() function in my code that takes variable arguments; variable in type and number. Like so:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nvoid log(int code);\ntemplate&amp;amp;lt; typename T0 &amp;amp;gt; void log(int code, T0 const&amp;amp;amp; t0);\ntemplate&amp;amp;lt; typename T0, typename T1 &amp;amp;gt; void log(int code, T0 const&amp;amp;amp; t0, T1 const&amp;amp;amp; t1);\n...\n<\/pre>\n<p>That gets old really fast, and this is essentially repeating the same information over and over again. There\u2019s no value in each individual function. It\u2019s just more of the same. In the future, when more arguments are needed, and that\u2019ll always happen, additional copy and pastes will need to be made.<\/p>\n<p>The simplest way to repeat code is with the BOOST_PP_REPEAT macro. When working with the preprocessor I tend to write the code normally, and then convert it piece by piece into generated code. To start with, define the number of log() functions needed:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#define MAX_LOG_ARGS 5\n<\/pre>\n<p>When more arguments are needed, all that needs to change is this one define. It could even be passed in on the command line to the compiler.<\/p>\n<p>The next step is to define the function itself and start repeating it:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &quot;boost\/preprocessor\/repetition\/repeat.hpp&quot;\n\n#define MAX_LOG_ARGS 5\n#define LOG(z, i, _) void log(int code);\n\nBOOST_PP_REPEAT(MAX_LOG_ARGS, LOG, _)\n\n#undef LOG\n#undef MAX_LOG_ARGS\n<\/pre>\n<p>It\u2019s considered best practice to undefine the macros as soon as you don\u2019t need them anymore. As seen above, the macros aren\u2019t needed again after the expansion of BOOST_PP_REPEAT.<\/p>\n<p>This will produce:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nvoid log(int code);\nvoid log(int code);\nvoid log(int code);\nvoid log(int code);\nvoid log(int code);\n<\/pre>\n<p>Not even close to what is needed, but it is a good start. The arguments to the BOOST_PP_REPEAT macro are:<\/p>\n<ul>\n<li>MAX_LOG_ARGS \u2013 The number of times to repeat.<\/li>\n<li>LOG \u2013 The macro to repeat.<\/li>\n<li>_ \u2013 This is any extra data that should be passed to the macro that is being repeated. The underscore is generally used when there isn\u2019t any extra data.<\/li>\n<\/ul>\n<p>The arguments to the LOG macro are:<\/p>\n<ul>\n<li>z \u2013 An internal thing to the library. It helps with recursively calling BOOST_PP_REPEAT. This can be ignored.<\/li>\n<li>i \u2013 The current repetition index, e.g. 0, 1, 2, 3, and 4 in this example.<\/li>\n<li>_ \u2013 This is whatever was passed in as the last argument to the BOOST_PP_REPEAT macro.<\/li>\n<\/ul>\n<p>I won\u2019t cover all the arguments for all the macros, as that would just be repeating the information in the <a href=\"http:\/\/www.boost.org\/doc\/libs\/1_55_0\/libs\/preprocessor\/doc\/index.html\">library documentation<\/a>, but the above should be a good primer.<\/p>\n<p>The log() function needs template specifications, so let\u2019s add them in:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &quot;boost\/preprocessor\/repetition\/repeat.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/enum_params.hpp&quot;\n\n#define MAX_LOG_ARGS 5\n#define LOG(z, i, _) \\\n   template &amp;amp;lt; BOOST_PP_ENUM_PARAMS(i, typename T) &amp;amp;gt; \\\n   void log(int code);\n\nBOOST_PP_REPEAT(MAX_LOG_ARGS, LOG, _)\n\n#undef LOG\n#undef MAX_LOG_ARGS\n<\/pre>\n<p>The BOOST_PP_ENUM_PARAMS macro is perfect for this situation; think of it as a specialized BOOST_PP_REPEAT. It\u2019ll repeat its second argument the number of times specified in the first. This lets us use the i argument passed into the LOG macro. This will produce:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\ntemplate &amp;amp;lt; &amp;amp;gt; void log(int code);\ntemplate &amp;amp;lt; typename T0 &amp;amp;gt; void log(int code);\ntemplate &amp;amp;lt; typename T0, typename T1 &amp;amp;gt; void log(int code);\ntemplate &amp;amp;lt; typename T0, typename T1, typename T2 &amp;amp;gt; void log(int code);\ntemplate &amp;amp;lt; typename T0, typename T1, typename T2, typename T3 &amp;amp;gt; void log(int code);\n<\/pre>\n<p>This would be great except for when i equals 0. In that case we were left with an empty template specification. Luckily, the preprocessor can also do conditionals:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &quot;boost\/preprocessor\/control\/expr_if.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/repeat.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/enum_params.hpp&quot;\n\n#define MAX_LOG_ARGS 5\n#define LOG(z, i, _) \\\n   BOOST_PP_EXPR_IF(i, template &amp;amp;lt; BOOST_PP_ENUM_PARAMS(i, typename T) &amp;amp;gt;) \\\n   void log(int code);\n\nBOOST_PP_REPEAT(MAX_LOG_ARGS, LOG, _)\n\n#undef LOG\n#undef MAX_LOG_ARGS\n<\/pre>\n<p>The BOOST_PP_EXPR_IF macro will expand to its second argument if the first argument is greater than 0. That works perfectly for this situation. There is also a BOOST_PP_IF macro that provides if-else functionality.<\/p>\n<p>Next, the template types should be used to add arguments to the log() function. The BOOST_PP_ENUM_PARAMS function might be useful here again, but this situation is slightly different; both the type and the argument name to be enumerated. In addition, a comma needs to be added after the code argument when the number of arguments is greater than 0. This is all much easier than it sounds:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &quot;boost\/preprocessor\/control\/expr_if.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/repeat.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/enum_params.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/enum_trailing_binary_params.hpp&quot;\n\n#define MAX_LOG_ARGS 5\n#define LOG(z, i, _) \\\n   BOOST_PP_EXPR_IF(i, template &amp;amp;lt; BOOST_PP_ENUM_PARAMS(i, typename T) &amp;amp;gt;) \\\n   void log(int code BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, T, const&amp;amp;amp; t));\n\nBOOST_PP_REPEAT(MAX_LOG_ARGS, LOG, _)\n\n#undef LOG\n#undef MAX_LOG_ARGS\n<\/pre>\n<p>This is a common enough practice that Boost comes with one macro to do all of that, BOOST_PP_ENUM_TRAILING_BINARY_PARAMS. The result:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nvoid log(int code);\ntemplate &amp;amp;lt; typename T0 &amp;amp;gt;\n   void log(int code, T0 const&amp;amp;amp; t0);\ntemplate &amp;amp;lt; typename T0, typename T1 &amp;amp;gt;\n   void log(int code, T0 const&amp;amp;amp; t0, T1 const&amp;amp;amp; t1);\ntemplate &amp;amp;lt; typename T0, typename T1, typename T2 &amp;amp;gt;\n   void log(int code, T0 const&amp;amp;amp; t0, T1 const&amp;amp;amp; t1, T2 const&amp;amp;amp; t2);\ntemplate &amp;amp;lt; typename T0, typename T1, typename T2, typename T3 &amp;amp;gt;\n   void log(int code, T0 const&amp;amp;amp; t0, T1 const&amp;amp;amp; t1, T2 const&amp;amp;amp; t2, T3 const&amp;amp;amp; t3);\n<\/pre>\n<p>Wait\u2014something isn\u2019t quite right. The MAX_LOG_ARGS macro said the maximum number of log arguments should be 5, but this only produces log() functions that take four. Yet again, the preprocessor amazes; it can do math:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &quot;boost\/preprocessor\/arithmetic\/inc.hpp&quot;\n#include &quot;boost\/preprocessor\/control\/expr_if.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/repeat.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/enum_params.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/enum_trailing_binary_params.hpp&quot;\n\n#define MAX_LOG_ARGS 5\n#define LOG(z, i, _) \\\n   BOOST_PP_EXPR_IF(i, template &amp;amp;lt; BOOST_PP_ENUM_PARAMS(i, typename T) &amp;amp;gt;) \\\n   void log(int code BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, T, const&amp;amp;amp; t));\n\nBOOST_PP_REPEAT(BOOST_PP_INC(MAX_LOG_ARGS), LOG, _)\n\n#undef LOG\n#undef MAX_LOG_ARGS\n<\/pre>\n<p>The BOOST_PP_INC simply increments the MAX_LOG_ARGS macro so that the desired behavior is achieved; one additional log() function is generated:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nvoid log(int code);\ntemplate &amp;amp;lt; typename T0 &amp;amp;gt;\n   void log(int code, T0 const&amp;amp;amp; t0);\ntemplate &amp;amp;lt; typename T0, typename T1 &amp;amp;gt;\n   void log(int code, T0 const&amp;amp;amp; t0, T1 const&amp;amp;amp; t1);\ntemplate &amp;amp;lt; typename T0, typename T1, typename T2 &amp;amp;gt;\n   void log(int code, T0 const&amp;amp;amp; t0, T1 const&amp;amp;amp; t1, T2 const&amp;amp;amp; t2);\ntemplate &amp;amp;lt; typename T0, typename T1, typename T2, typename T3 &amp;amp;gt;\n   void log(int code, T0 const&amp;amp;amp; t0, T1 const&amp;amp;amp; t1, T2 const&amp;amp;amp; t2, T3 const&amp;amp;amp; t3);\ntemplate &amp;amp;lt; typename T0, typename T1, typename T2, typename T3, typename T4 &amp;amp;gt;\n   void log(\n      int code,\n      T0 const&amp;amp;amp; t0,\n      T1 const&amp;amp;amp; t1,\n      T2 const&amp;amp;amp; t2,\n      T3 const&amp;amp;amp; t3,\n      T4 const&amp;amp;amp; t4);\n<\/pre>\n<p>Other arithmetic operators are available, including BOOST_PP_ADD, BOOST_PP_SUB, BOOST_PP_MUL, and BOOST_PP_DIV.<\/p>\n<p>To finish off this example, this is a simple definition of the log() function:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &quot;boost\/preprocessor\/arithmetic\/inc.hpp&quot;\n#include &quot;boost\/preprocessor\/cat.hpp&quot;\n#include &quot;boost\/preprocessor\/control\/expr_if.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/repeat.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/enum_params.hpp&quot;\n#include &quot;boost\/preprocessor\/repetition\/enum_trailing_binary_params.hpp&quot;\n#include &quot;boost\/preprocessor\/stringize.hpp&quot;\n\n#define MAX_LOG_ARGS 5\n#define STREAM_PARAM(z, i, _) \\\n   BOOST_PP_EXPR_IF(i, &amp;amp;lt;&amp;amp;lt; &quot;,&quot;) &amp;amp;lt;&amp;amp;lt; BOOST_PP_STRINGIZE(i=) &amp;amp;lt;&amp;amp;lt; BOOST_PP_CAT(t, i)\n#define LOG(z, i, _) \\\n   BOOST_PP_EXPR_IF(i, template &amp;amp;lt; BOOST_PP_ENUM_PARAMS(i, typename T) &amp;amp;gt;) \\\n   void log(int code BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, T, const&amp;amp;amp; t)) \\\n   { \\\n      std::cout &amp;amp;lt;&amp;amp;lt; &quot;code=&quot; &amp;amp;lt;&amp;amp;lt; code BOOST_PP_EXPR_IF(i, &amp;amp;lt;&amp;amp;lt; &quot;,&quot;) \\\n         BOOST_PP_REPEAT(i, STREAM_PARAM, _) \\\n         &amp;amp;lt;&amp;amp;lt; std::endl; \\\n   }\n\nBOOST_PP_REPEAT(BOOST_PP_INC(MAX_LOG_ARGS), LOG, _)\n\n#undef LOG\n#undef STREAM_PARAM\n#undef MAX_LOG_ARGS\n<\/pre>\n<p>This merely streams the arguments to standard out, but it shows how BOOST_PP_REPEAT can be used recursively. This also uses two new macros; the BOOST_PP_CAT macro, which is a safer ## (concatenation) operator, and the BOOST_PP_STRINGIZE macro, which is a safer # (stringification) operator. Besides being safer than their operator counterparts, they also show much more intent.<\/p>\n<p>We now have a log function that is easy to use:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &amp;amp;lt;cstdlib&amp;amp;gt;\n\n#include &quot;log.h&quot;\n\nint main(int argc, char* argv[])\n{\n   log(0);\n   log(1, &quot;Hello&quot;);\n   log(2, &quot;Hello&quot;, &quot;World&quot;, 6, 7.0f);\n\n   return EXIT_SUCCESS;\n}\n<\/pre>\n<p>Output:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\ncode = 0\ncode = 1, 0 = Hello\ncode = 2, 0 = Hello, 1 = World, 2 = 6, 3 = 7\n<\/pre>\n<h2>Sequences<\/h2>\n<p>With the same goal of reducing repetition, preprocessor sequences can help. If many very similar functions are required, the parts that are unique can be extracted, and the parts that remain can be implemented just once.<\/p>\n<p>To demonstrate, consider these functions:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\ntemplate&amp;amp;lt; typename T &amp;amp;gt; T add(T t0, T t1)\n{\n   return t0 + t1;\n}\n\ntemplate&amp;amp;lt; typename T &amp;amp;gt; T sub(T t0, T t1)\n{\n   return t0 - t1;\n} \n\ntemplate&amp;amp;lt; typename T &amp;amp;gt; T mul(T t0, T t1)\n{\n   return t0 * t1;\n} \n\ntemplate&amp;amp;lt; typename T &amp;amp;gt; T div(T t0, T t1)\n{\n   return t0 \/ t1;\n}\n<\/pre>\n<p>They are pretty repetitive. To eliminate the repetition, sequences can be used to define just the parts that are different. While the structure or algorithm of the functions is defined elsewhere.<\/p>\n<p>Instead of building this up from scratch, which is left to the reader, the solution would look like this:<\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &quot;boost\/preprocessor\/seq\/elem.hpp&quot;\n#include &quot;boost\/preprocessor\/seq\/for_each.hpp&quot;\n\n#define OPERATIONS \\\n   ((add)(+)) \\\n   ((sub)(-)) \\\n   ((mul)(*)) \\\n   ((div)(\/))\n\n#define INIT_OPERATION(r, _, elem) \\\n   template&amp;amp;lt; typename T &amp;amp;gt; T BOOST_PP_SEQ_ELEM(0, elem)(T t0, T t1) \\\n   { \\\n      return t0 BOOST_PP_SEQ_ELEM(1, elem) t1; \\\n   }\n\nBOOST_PP_SEQ_FOR_EACH(INIT_OPERATION, _, OPERATIONS)\n\n#undef INIT_OPERATION\n#undef OPERATIONS\n<\/pre>\n<p>As can be seen, the names of the functions and the corresponding operators can be defined in the OPERATIONS macro, and the body of the function in the INIT_OPERATION macro, which is repeated once for each operation. Adding a new operation, perhaps %, would only take a second.<\/p>\n<h1>Wrap-up<\/h1>\n<p>Avoiding duplication, whether data, logic, algorithm, or code should be avoided whenever possible. The preprocessor is only one of many tools that can assist in that regard, however, it is one of the easiest to integrate into existing code, and it already has support from IDEs and the build system.<\/p>\n<p>Obviously the preprocessor must be used carefully. The pitfalls of macros, that I was warned against early on, must still be avoided, but the utility of the preprocessor should be embraced to drive out repetition and to enhance code when possible.<\/p>\n<p>The Boost Preprocessor library has many more macros that I haven\u2019t touched on as I only covered ones that I have personally used in code. I hope that even this small subset can find a place in your tool belt and use in your code.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction I have always felt like there is a dearth of cohesive C\/C++ education after school. Each software engineer seems to be on their own when it comes to learning new features, how to use a new library, or what the best practices are for common situations. This newsletter is my attempt to share some [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[6,7],"_links":{"self":[{"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/posts\/18"}],"collection":[{"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/comments?post=18"}],"version-history":[{"count":6,"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/posts\/18\/revisions"}],"predecessor-version":[{"id":55,"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/posts\/18\/revisions\/55"}],"wp:attachment":[{"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/media?parent=18"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/categories?post=18"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.causticlabs.com\/index.php\/wp-json\/wp\/v2\/tags?post=18"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}