Upload
lactrious
View
177
Download
2
Embed Size (px)
DESCRIPTION
c++ preprocessor programming for explanation of boost pp
Citation preview
Preprocessor programming
2013. 08. 23.
최재영
Motivation
• Don’t Repeat Yourself!
2
template <class T>DoAsync(void (T::*member)()) {}template <class T, class A1>DoAsync(void (T::*member)(), A1 a1) {}template <class T, class A1, class A2>DoAsync(void (T::*member)(), A1 a1, A2 a2) {}template <class T, class A1, class A2, class A3>DoAsync(void (T::*member)(), A1 a1, A2 a2, A3 a3) {}template <class T, class A1, class A2, class A3, class A4>DoAsync(void (T::*member)(), A1 a1, A2 a2, A3 a3, A4 a4) {}
enum SomeType {TypeA,TypeB,
};
const TCHAR* GetSomeTypeName(SomeType type) {if (type == TypeA) return _T("TypeA");if (type == TypeB) return _T("TypeB");return _T("");
}
Why?
• generate code that cannot be generated by template
• or generate boilerplate template code
3
concat token
repetition
multi-pass generation
a ## b
#include "repl_a.h"#include "spec.h"#include "repl_b.h"#include "spec.h"
#define TARGET "spec.h"#include "iteration.h"
#define DECL(name) \template <REPEAT(MAX_SIZE, class T)>
흐름4
X-Macro
repetition
Boost PP
horizontalvertical
Fundamentals5
// 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.
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?
X-Macro
• generating repeating code structures at compile time
7
enum SomeType {ST_SOME,ST_OTHER
};
inline const TCHAR* GetNameFromSomeType(SomeType type) {if (type == ST_SOME) return _T("ST_SOME");if (type == ST_OTHER) return _T("ST_OTHER");return _T("");
}
inline SomeType GetSomeTypeFromName(const TCHAR* str) {if (_tcsicmp(str, _T("ST_SOME") == 0) return ST_SOME;if (_tcsicmp(str, _T("ST_OTHER") == 0) return ST_OTHER;return static_cast<SomeType>(-1);
}
X-Macro (cont.)8
ENUM_BEGIN(SomeType)ENUM(ST_SOME)ENUM(ST_OTHER)
ENUM_END(SomeType)
#define ENUM_BEGIN(name) enum name {#define ENUM(name) name,#define ENUM_END(name) };
#define ENUM_BEGIN(name) \inline const TCHAR* GetNameFrom##name##(name type) {
#define ENUM(name) if (type == name) return _T(#name);#define ENUM_END(name) return _T(""); }
#define ENUM_BEGIN(name) \inline name Get##name##FromName(const TCHAR* str) {
#define ENUM(name) if (_tcsicmp(str, #name) == 0) return name;#define ENUM_END(name) return static_cast<name>(-1); }
sometype_spec.h
enum_decl_gen.h
enum_to_str_gen.h
str_to_enum_gen.h
X-Macro (cont.)9
#include "enum_decl_gen.h"#include "sometype_spec.h"
enums.h
#include "enum_to_str_gen.h"#include "sometype_spec.h"
#include "enum_gen_reset.h"
#include "str_to_enum_gen.h"#include "sometype_spec.h"
enums.cpp
#undef ENUM_BEGIN#undef ENUM#undef ENUM_END
enum_gen_reset.h
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
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
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!
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)
#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
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
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!
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 ... ?
Vertical Repetition (cont.)
• size ≠ limit
18
// ...
#elif CURRENT < LIMIT# if CURRENT == 0# undef CURRENT# define CURRENT 1
// ...
repeater.h
repeater.h(TARGET, SIZE, LIMIT)
Vertical Repetition (cont.)19
main.cpp
#define SIZE 3template <class RCOMMA_IF_NONZERO(SIZE)
REPEAT(SIZE, REPEAT_PARAM)>struct test{};
#define TARGET "spec.h"#define LIMIT SUB(SIZE, 1)
#include "repeater.h"
template <class RCOMMA_IF_NONZERO(CURRENT)REPEAT(CURRENT, REPEAT_PARAM)>
struct test<RCOMMA_IF_NONZERO(CURRENT)REPEAT(CURRENT, REPEAT_VAR)COMMA_IF_NONZERO(SUB(SIZE, CURRENT))REPEAT(SUB(SIZE, CURRENT), REPEAT_NONE)>
{};
spec.h
file iteration
generate partial specialization
generate original template
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
Vertical Repetition (cont.)21
#if !defined(IS_REPEATING)# define SIZE 3template <class R
COMMA_IF_NONZERO(SIZE)REPEAT(CURRENT, REPEAT_PARAM)>
struct test {};# define TARGET "test.h"# define LIMIT SUB(SIZE, 1)# include "repeater.h"#elsetemplate <class R
COMMA_IF_NONZERO(CURRENT)REPEAT(CURRENT, REPEAT_PARAM)>
struct test<RCOMMA_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
boost pp
• boost preprocess library
– BOOST_PP_CAT
– BOOST_PP_ENUM_PARAMS
– BOOST_PP_REPEAT
– BOOST_PP_COMMA_IF
– BOOST_PP_SUB
– BOOST_PP_DEC
– BOOST_PP_WHILE
– BOOST_PP_ITERATE
22
boost pp (cont.)
• many predefined macros functions
– Arithmetic, Logical, and Comparison Operations
– Control Structures
– Token Pasting(argument selection)
– Data Types(sequence, tuple, array, list)
• well-optimized expand complexity
23
# define BOOST_PP_NODE_ENTRY_256(p) \BOOST_PP_NODE_128(p)(p)(p)(p)(p)(p)(p)(p)
# define BOOST_PP_NODE_ENTRY_128(p) \BOOST_PP_NODE_64(p)(p)(p)(p)(p)(p)(p)
// ...# define BOOST_PP_NODE_ENTRY_2(p) BOOST_PP_NODE_1(p)
boost pp (cont.)
• supports 256 reentrancy
• supports 3 dimension (concurrently expandable count)
24
# define BOOST_PP_DEC_0 0# define BOOST_PP_DEC_1 0// ...# define BOOST_PP_DEC_255 254# define BOOST_PP_DEC_256 255
# define BOOST_PP_REPEAT_1(c, m, d) BOOST_PP_REPEAT_1_I(c, m, d)# define BOOST_PP_REPEAT_2(c, m, d) BOOST_PP_REPEAT_2_I(c, m, d)# define BOOST_PP_REPEAT_3(c, m, d) BOOST_PP_REPEAT_3_I(c, m, d)
Summary
• Don't repeat yourself!
• reduce boilerplate code using preprocess programming
• but, your compile time is also boosted!
25