The document discusses techniques for reducing repetitive code using C/C++ preprocessor programming. It covers macros like X-Macro for generating repeating code structures, horizontal and vertical repetition using chaining and recursion of macros, and Boost Preprocessor library which provides optimized macros for tasks like repetition and token pasting that support high levels of reentrancy. The goal is to avoid duplicating code and generate boilerplate code at compile-time through clever use of the preprocessor.
5. Fundamentals
5
// object-like macro
#define <identifier> <replacement token list>
// function-like macro, note parameters
#define <identifier>(<parameter list>) <replacement token list>
// local macro
#define <identifier>
/* do something */
#undef <identifier>
• Macro expansion in the preprocessor is entirely functional.
But the preprocessor disallows recursion.
6. Fundamentals (cont.)
6
// reentrancy problem
#define CONCAT(a, b) a ## b
#define AB(x, y) CONCAT(x, y)
CONCAT(A, B(p, q)) // CONCAT(p, q), not pq
// solving the one-depth reentrancy problem
#define CONCAT2(a, b) a ## b
#define AB(x, y) CONCAT(x, y)
#define CONCAT(a, b) CONCAT2(a, b)
CONCAT(A, B(p, q)) // pq
• How many recursion-depth does it support?
• How many case does it define?
10. Repetition
• horizontal repetition
• vertical repetition
10
template <class T>
void DoAsync(...);
template <class T, class A0>
void DoAsync(...);
template <class T, class A0, class A1>
void DoAsync(...);
template <class T, class A0, class A1, class A2>
void DoAsync(...);
template <class T, class A0, class A1, class A2, class A3>
void DoAsync(...);
vertical
horizontal
11. Horizontal Repetition (cont.)
• the preprocessor disallows recursion.
• all cases should be defined.
11
#define REPEAT_1(m) m(0)
#define REPEAT_2(m) REPEAT_1(m), m(1)
#define REPEAT_3(m) REPEAT_2(m), m(2)
#define REPEAT_4(m) REPEAT_3(m), m(3)
#define REPEAT_5(m) REPEAT_4(m), m(4)
// ...
#define REPEAT(c, m) CONCAT(REPEAT_, c)(m)
chaining
end condition
case selector
12. Horizontal Repetition (cont.)
12
generator#define REPEAT_PARAM(n) class T ## n
template <class R, REPEAT(4, REPEAT_PARAM)>
struct test_t {}; repeat count
template <class R, class T0, class T1, class T2, class T3>
struct test_t {}; repeated
expand!
13. Vertical Repetition (cont.)
• macro state & self-include
13
#if !defined(CURRENT)
# define CURRENT 0
# include "repeater.h"
#elif CURRENT < SIZE
# if CURRENT == 0
# undef CURRENT
# define CURRENT 1
# elif CURRENT == 1
# undef CURRENT
# define CURRENT 2
// ...
# endif
# include TARGET
# include "repeater.h"
#else
#endif
repeater.h
define initial state
self-include
self-include
target-include
state-machine
repeater.h(TARGET, SIZE)
14. #ifndef REPEAT_PARAM
#define REPEAT_PARAM(n) class T ## n
#endif
template <class R, REPEAT(CURRENT, REPEAT_PARAM)>
struct test_t {};
Vertical Repetition (cont.)
14
spec.h
iteration count
#define TARGET "spec.h"
#define SIZE 3
#include "repeater.h"
main.cpp
set macro parameter
call macro file function
15. Is it end?
15
template <class T0, class T1, class T2>
struct tiny_size {};
template <class T0, class T1>
struct tiny_size<T0, T1, none> {};
template <class T0>
struct tiny_size<T0, none, none> {};
template <>
struct tiny_size<none, none, none> {};
comma problem
need to sub function
seperate original template & partial specialization generator
16. COMMA_IF_NONZERO (helper)
16
#define COMMA_IF_NONZERO_0
#define COMMA_IF_NONZERO_1 ,
#define COMMA_IF_NONZERO_2 ,
#define COMMA_IF_NONZERO_3 ,
#define COMMA_IF_NONZERO_4 ,
#define COMMA_IF_NONZERO_5 ,
#define COMMA_IF_NONZERO(n) CONCAT(COMMA_IF_NONZERO_, n)
all cases should be defined!
17. SUB (helper)
17
// ...
#define SUB_33 0
#define SUB_20 2
#define SUB_21 1
#define SUB_22 0
#define SUB_10 1
#define SUB_11 0
#define SUB_00 0
#define SUB(a, b) CONCAT(CONCAT(SUB_, a), b)
all cases should be defined ... ?
18. Vertical Repetition (cont.)
• size ≠ limit
18
// ...
#elif CURRENT < LIMIT
# if CURRENT == 0
# undef CURRENT
# define CURRENT 1
// ...
repeater.h
repeater.h(TARGET, SIZE, LIMIT)
20. Vertical Repetition (cont.)
20
• Local iteration: using macro state
#if !defined(IS_REPEATING)
# define IS_REPEATING 1
# include "repeater.h"
#else
# if !defined(CURRENT)
# define CURRENT 0
# include "repeater.h"
# elif CURRENT <= LIMIT
// ...
# else
# undef IS_REPEATING
# endif
#endif
initial state
iterating state
21. Vertical Repetition (cont.)
21
#if !defined(IS_REPEATING)
# define SIZE 3
template <class R
COMMA_IF_NONZERO(SIZE)
REPEAT(CURRENT, REPEAT_PARAM)>
struct test {};
# define TARGET "test.h"
# define LIMIT SUB(SIZE, 1)
# include "repeater.h"
#else
template <class R
COMMA_IF_NONZERO(CURRENT)
REPEAT(CURRENT, REPEAT_PARAM)>
struct test<R
COMMA_IF_NONZERO(CURRENT)
REPEAT(CURRENT, REPEAT_VAR)
COMMA_IF_NONZERO(SUB(SIZE, CURRENT))
REPEAT(SUB(SIZE, CURRENT), REPEAT_NONE)> {};
#endif
iterating state
initial state
repetition entry-point