<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ColonelPanic &#187; preprocessor</title>
	<atom:link href="http://colonelpanic.net/tag/preprocessor/feed/" rel="self" type="application/rss+xml" />
	<link>http://colonelpanic.net</link>
	<description>Dumping our corps so you don&#039;t have to</description>
	<lastBuildDate>Mon, 30 Jan 2012 17:50:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Boost.Preprocessors Sequences</title>
		<link>http://colonelpanic.net/2010/07/boost-preprocessors-sequences/</link>
		<comments>http://colonelpanic.net/2010/07/boost-preprocessors-sequences/#comments</comments>
		<pubDate>Sat, 03 Jul 2010 16:18:13 +0000</pubDate>
		<dc:creator>Georg Fritzsche</dc:creator>
				<category><![CDATA[General Development]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[metaprogramming]]></category>
		<category><![CDATA[preprocessor]]></category>

		<guid isPermaLink="false">http://colonelpanic.net/?p=205</guid>
		<description><![CDATA[After recently answering a question on Stackoverflow using Boost.Preprocessor, i wondered how the sequences, e.g. SUM_MACRO((1)(2)(3)), actually work. Implementing Macros operating on sequences Sequences give you a convenient array-like data-structure wich can be passed to macros: #define HEAD(sequence) \ BOOST_PP_SEQ_ELEM(0, sequence) std::cout]]></description>
			<content:encoded><![CDATA[<p>After recently <a href="http://stackoverflow.com/questions/3150700/need-meta-programming-magic-to-define-a-mother-load-of-bit-fields-in-an-error-fre/3151243#3151243">answering</a> a question on Stackoverflow using <a href="http://www.boost.org/doc/libs/1_43_0/libs/preprocessor/doc/index.html">Boost.Preprocessor</a>, i wondered how the <a href="http://www.boost.org/doc/libs/1_43_0/libs/preprocessor/doc/data/sequences.html">sequences</a>, e.g. <code>SUM_MACRO((1)(2)(3))</code>, actually work.</p>
<p><span id="more-205"></span></p>
<h2>Implementing Macros operating on sequences</h2>
<p>Sequences give you a convenient array-like data-structure wich can be passed to macros:</p>
<pre lang="c++">
#define HEAD(sequence) \
    BOOST_PP_SEQ_ELEM(0, sequence)

std::cout << HEAD((0)(1)(2)); // prints "0"
</pre>
<p>Now how can that be implemented? First there are two characters that have special status for the preprocessor: commas and parentheses.<br />
Parentheses can be used to </p>
<ul>
<li>wrap expressions to be left alone by macro expansion, e.g. because they contain commas</li>
<li>can be bound to macro names as parameter lists</li>
</ul>
<p>The binding of parameter lists doesn't have to happen immediately, so the following works fine:</p>
<pre lang="c++">
#define IDENTITY(x) x
#define HEAD(sequence) IDENTITY sequence
std::cout << HEAD((42)); // prints "42"
</pre>
<p>The macro-expansion here is the following:</p>
<pre lang="c++">
HEAD((42))
IDENTITY (42)
42
</pre>
<p>That already works fine for a one-element sequence, but what if it had more elements:</p>
<pre lang="c++">
std::cout << HEAD((42)(23));
// results in:
std::cout << 42(23);
</pre>
<p>... which is obviously wrong. We need to get rid of the rest of the sequence by going through another macro:</p>
<pre lang="c++">
#define FIRST(x) x, DOESNT_EXIST
#define HEAD(sequence) FIRST sequence
std::cout << HEAD((42)(23));
</pre>
<p>This now results in:</p>
<pre lang="c++">
HEAD((42)(23))
FIRST (42)(23) // FIRST binds (42)
42, DOESNT_EXIST(23)
</pre>
<p>Passing this result through another macro that takes two arguments, we can ignore the second part:</p>
<pre lang="c++">
#define HEAD(sequence) IGNORE_SECOND(FIRST sequence)
#define FIRST(x) x, FOO
#define IGNORE_SECOND(x) IGNORE_SECOND_I(x) // needed for expansion of x
#define IGNORE_SECOND_I(x, _) x
</pre>
<p>Which now expands to:</p>
<pre lang="c++">
HEAD((42)(23))
IGNORE_SECOND(FIRST (42)(23)) // FIRST binds (42)
IGNORE_SECOND_I(42, DOESNT_EXIST(23))
42
</pre>
<h2>Getting elements by index</h2>
<p>Now the macros we pass the comma-separated expansion to don't have to throw away the second part:</p>
<pre lang="c++">
#define SECOND(sequence) IGNORE_SECOND(TAIL sequence)
#define TAIL(x) FIRST // throw away first element
</pre>
<p>... with which we get something like the following expansion:</p>
<pre lang="c++">
SECOND((1)(2)(3))
IGNORE_SECOND(TAIL (1)(2)(3))
IGNORE_SECOND_I(FIRST (2)(3))
IGNORE_SECOND_I(2, DOESNT_EXIST(3))
2
</pre>
<p>Now combining that with the concatenation operator <code>##</code> we can define macros that operate index-based:</p>
<pre lang="c++">
#define GET_BY_INDEX(index, sequence) IGNORE_SECOND( GET_##index sequence )
#define GET_0(x) x, DOESNT_EXIST
#define GET_1(_) GET_0
#define GET_2(_) GET_1
// ...
</pre>
<p>... which could lead to the following expansion:</p>
<pre lang="c++">
GET_BY_INDEX(2, (1)(2)(3)(4))
IGNORE_SECOND(GET_2 (1)(2)(3)(4))
IGNORE_SECOND_I(GET_1 (2)(3)(4))
IGNORE_SECOND_I(GET_0 (3)(4))
IGNORE_SECOND_I(3, DOESNT_EXIST(4))
3
</pre>
<h2>Counting elements</h2>
<p>To get the size of a sequence the elements in it need to be counted. The trick here is that substitution for macros that take arguments stops if there are no parameter-lists left that could be bound, so the following:</p>
<pre lang="c++">
#define SIZE(sequence) SIZE_0 sequence
#define SIZE_0(_) SIZE_1
#define SIZE_1(_) SIZE_2
#define SIZE_2(_) SIZE_3
// ...
</pre>
<p>would expand <code>SIZE((1)(2))</code> to <code>SIZE_2</code>. All that is left then is to map that name to a number:</p>
<pre lang="c++">
#define SIZE(sequence) \
    CONCAT(SIZE_, SIZE_0 sequence) // concatenate SIZE_ with SIZE_N
#define CONCAT(a, b) CONCAT_I(a, b) // allow for macro expansion
#define CONCAT_I(a, b) a ## b
#define SIZE_SIZE_0 0
#define SIZE_SIZE_1 1
#define SIZE_SIZE_2 2
// ...
</pre>
<p>... which would lead to expansions like:</p>
<pre lang="c++">
SIZE((1)(2))
CONCAT(SIZE_, SIZE_0 (1)(2))
CONCAT_I(SIZE_, SIZE_0 (1)(2))
CONCAT_I(SIZE_, SIZE_1 (2))
CONCAT_I(SIZE_, SIZE_2)
SIZE_ ## SIZE_2
SIZE_SIZE_2
2
</pre>
<p>- Georg</p>
]]></content:encoded>
			<wfw:commentRss>http://colonelpanic.net/2010/07/boost-preprocessors-sequences/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

