Introduce to CPP ~黒魔術へのいざない~5. マクロおさらい
#define HOGE AAAAAA
HOGE // AAAAAA に置換される
#define FUNC(a, b) a b a
FUNC(X, Y) // X Y X に置換される
#define CAT(a, b) a ## b
CAT(X, Y) // トークン連結して XY に置換される
#define STRINGIZE(a) #a
STRINGIZE(HOGE) // 文字列化して"Hoge"に置換される
#define FUNC2(a, ...) a __VA_ARGS__ a
FUNC2(A, X, Y, Z) // A X, Y, Z A に置換される (可変長引数)
11. CodeGen 完成形イメージ
enum Type{
Dog,
Cat,
Human,
};
const char* getName(Type t){
switch(t){
case Dog:
return "Dog";
case Cat:
return "Cat";
case Human:
return "Human";
}
}
#define TYPES (Dog, Cat, Human)
#define GEN_ENUM(v) v,
enum Type{
FOR_EACH(GEN_ENUM, TYPES)
};
#define GEN_FUNC(v) ¥
case v : return STRINGIZE(v);
const char* getName(Type t){
switch(t){
FOR_EACH(GEN_FUNC, TYPES)
}
}
13. Tupleの要素数を得るマクロ
#define TUPLE_SIZE_D(e0, e1, e2, e3, size, ...) size
#define TUPLE_SIZE_I(...) TUPLE_SIZE_D(__VA_ARGS__, 4, 3, 2, 1)
#define TUPLE_SIZE(tuple) TUPLE_SIZE_I tuple
TUPLE_SIZE( (a, b, c) )
// => TUPLE_SIZE_I (a, b, c)
// => TUPLE_SIZE_D (a, b, c, 4, 3, 2, 1)
// => 3
14. Tupleの特定の要素を得る
#define CAT(a, b) a ## b
#define TUPLE_GET_0(e0, ...) e0
#define TUPLE_GET_1(e0, e1, ...) e1
#define TUPLE_GET_2(e0, e1, e2, ...) e2
#define TUPLE_GET_3(e0, e1, e2, e3, ...) e3
#define TUPLE_GET_I(i, tuple) CAT(TUPLE_GET_, i) tuple
#define TUPLE_GET(i, tuple) TUPLE_GET_I(i, tuple)
TUPLE_GET(1, (a, b))
// => TUPLE_GET_I(1, (a, b))
// => CAT(TUPLE_GET_, 1) (a, b)
// => TUPLE_GET_1 (a, b)
// => b
15. 繰り返す
#define REPEAT_I4(f, p, n) REPEAT_I3(f, p, n) f( p (3) n )
#define REPEAT_I3(f, p, n) REPEAT_I2(f, p, n) f( p (2) n )
#define REPEAT_I2(f, p, n) REPEAT_I1(f, p, n) f( p (1) n )
#define REPEAT_I1(f, p, n) f( p (0) n )
#define REPEAT_I(i, f, p, n) CAT(REPEAT_I, i)(f, p, n)
#define REPEAT(i, f, p, n) REPEAT_I(i, f, p, n)
REPEAT(3, F, P, N)
// => REPEAT_I(3, F, P, N)
// => CAT(REPEAT_I, 3)(F, P, N)
// => REPEAT_I3(F, P, N)
// => REPEAT_I2(F, P, N) F( P (2) N )
// => REPEAT_I1(F, P, N) F( P (1) N ) F( P (2) N )
// => F( P (0) N ) F ( P (1) N ) F ( P (2) N )
16. Foreachを書く
#define FOR_EACH_FUNC_I(i) CAT(TUPLE_GET_, i)
#define FOR_EACH(tuple, func) ¥
REPEAT(TUPLE_SIZE(tuple), func, FOR_EACH_FUNC_I, tuple)
FOR_EACH( (a, b, c), func )
// => REPEAT(TUPLE_SIZE((a, b, c)), func, FOR_EACH_FUNC_I, (a, b, c)
// => REPEAT(3, func, FOR_EACH_FUNC_I, (a, b, c)
// => func(FOR_EACH_FUNC_I (0) (a, b, c))
func(FOR_EACH_FUNC_I (1) (a, b, c))
func(FOR_EACH_FUNC_I (2) (a, b, c))
// => func(TUPLE_GET_0(a, b, c))
func(TUPLE_GET_1(a, b, c))
func(TUPLE_GET_2(a, b, c))
// => func(a) func(b) func(c)
17. 完成!
#define TYPES (Dog, Cat, Human)
#define GEN_ENUM(v) v,
enum Type{
FOR_EACH(TYPES, GEN_ENUM)
};
#define GEN_FUNC(v) case v : return STRINGIZE(v);
const char* getName(Type t){
switch(t){
FOR_EACH(TYPES, GEN_FUNC)
}
}
18. 完成!
#define TYPES (Dog, Cat, Human)
#define GEN_ENUM(v) v,
enum Type{
GEN_ENUM(Dog) GEN_ENUM(Cat) GEN_ENUM(Human)
};
#define GEN_FUNC(v) case v : return STRINGIZE(v);
const char* getName(Type t){
switch(t){
GEN_FUNC(Dog)
GEN_FUNC(Cat)
GEN_FUNC(Human)
}
}
FOR_EACH( (a, b, c), func )
// => func(a) func(b) func(c)
19. 完成!
#define TYPES (Dog, Cat, Human)
#define GEN_ENUM(v) v,
enum Type{
Dog, Cat, Human,
};
#define GEN_FUNC(v) case v : return STRINGIZE(v);
const char* getName(Type t){
switch(t){
case Dog: return "Dog";
case Cat: return "Cat";
case Human: return "Human";
}
}
GEN_ENUM(v)
// => v,
GEN_FUNC(v)
// => case v: return “v”;
20. 人間向け (Boost.PP)
#define TYPES (Dog)(Cat)(Human)
#define GEN_ENUM(v) v,
enum Type{
BOOST_PP_SEQ_FOR_EACH(GEN_ENUM, _, TYPES)
};
#define GEN_FUNC(v) case v : return STRINGIZE(v);
const char* getName(Type t){
switch(t){
BOOST_PP_SEQ_FOR_EACH(GEN_FUNC, _, TYPES)
}
}