ぼくのかんがえたさいきょうのぱたーんまっち。
以前twitterで、@kinaba先生にあおられたのを思い出したので、冬休みのリハビリがてら作ってみました。c++0x 版パターンマッチ。できたのを見ると厨二病全開です、はい。
以下みたいなのができます。とりあえず書き方。
#define match PHOENIX_MATCH #define with PHOENIX_WITH match (expr) { with (ptn1) { ... } with (ptn2) { ... } ... }
switch-case のまねです。はい。ptn1 -> ptn2 -> ... の順で評価してマッチしたら中を実行後 match から出る。
ptnの中身は以下の4種類
- 式との比較
#define match PHOENIX_MATCH #define with PHOENIX_WITH match (expr) { with (value) { // expr == value のときだけ実行 } }
- 変数のbind
#define match PHOENIX_MATCH #define with PHOENIX_WITH #define ref PHOENIX_REF match (expr) { with (ref(var)) { // 変数 var は expr への束縛 } }
- 何でもマッチ
#define match PHOENIX_MATCH #define with PHOENIX_WITH match (expr) { with (_) { // 任意の expr とマッチ } }
- struct/classとマッチ
#define match PHOENIX_MATCH #define with PHOENIX_WITH #define ptn PHOENIX_PTN #define ref PHOENIX_REF struct A { int x, y; }; DECLARE_PHOENIX_PATTERN(A, (x, y)); ... match (expr) { // expr は A型 with (ptn(A, (10, 20))) { // expr.x == 10 && expr.y == 20 でここにマッチ } with (ptn(A, (ref(x), _))) { // この中で x は expr.x, expr.y はなんでもマッチ } }
もうちょっと具体的なサンプル
#include <iostream> #include "phoenix/pattern.h" #define match PHOENIX_MATCH #define with PHOENIX_WITH #define ref PHOENIX_REF #define ptn PHOENIX_PTN class A { public: A(int x, int y) : x_(x), y_(y) {} virtual ~A() {} int x_; int y_; }; PHOENIX_DECLARE_PATTERN(A, (x_, y_)); bool operator==(const A& a, const A& b) { return a.x_ == b.x_ && a.y_ == b.y_; } class B : public A { public: B(int x, int y) : A(x, y) {} }; PHOENIX_DECLARE_PATTERN(B, (x_, y_)); class C : public A { public: C(int x, int y) : A(x, y) {} }; PHOENIX_DECLARE_PATTERN(C, (x_, y_)); class D { public: D(int z, int x, int y) : z_(z), a_(x, y) {} int z_; A a_; }; PHOENIX_DECLARE_PATTERN(D, (z_, a_)); using namespace std; int test(const A& arg) { const A const_a(1, 2); match (arg) { with (const_a) { cout << "first case" << endl; } with (ptn(A, (3, ref(a)))) { cout << "second case: " << a << endl; } with (ptn(B, (4, ref(a)))) { cout << "third case: " << a << endl; } with (ptn(C, (4, ref(a)))) { cout << "fourth case: " << a << endl; } with (_) { cout << "default case" << endl; } } } int test2(const D& d) { match(d) { with (ptn(D, (2, ptn(A, (3, 1))))) { cout << "first case: " << endl; } with (ptn(D, (_, ptn(A, (3, 1))))) { cout << "second case: " << endl; } with (ptn(D, (_, ptn(A, (ref(x), ref(y)))))) { cout << "third case: " << x << ", " << y << endl; } } } int main() { test(A(1, 2)); test(A(3, 2)); test(B(4, 3)); test(C(4, 2)); test(A(10, 20)); cout << endl; test2(D(2, 3, 1)); test2(D(3, 3, 1)); test2(D(1, 1, 2)); }
結果
first case second case: 2 third case: 3 fourth case: 2 default case first case: second case: third case: 1, 2
で、作ったヘッダ
#ifndef PHOENIX_PATTERN_H_ #define PHOENIX_PATTERN_H_ #include <utility> #include <boost/preprocessor/facilities/is_empty.hpp> #include <boost/preprocessor/control/iif.hpp> // Utilities. #define PHOENIX_IS_EMPTY BOOST_PP_IS_EMPTY #define PHOENIX_IF BOOST_PP_IIF #define PHOENIX_EAT(...) // Definition of control flow. #define PHOENIX_MATCH(expr) \ for (bool _phoenix_init = true, _phoenix_matched = false; \ _phoenix_init; _phoenix_init = false) \ for (const auto& _phoenix_expr = expr; \ _phoenix_init; _phoenix_init = false) \ for (auto _phoenix_tmp = std::make_pair(&_phoenix_expr, 0); \ _phoenix_init; _phoenix_init = false) #define PHOENIX_WITH(ptn) \ if (_phoenix_matched) {} else \ PHOENIX_WITH_IMPL(ptn) \ for (bool _phoenix_with_post = true; \ _phoenix_matched = true, _phoenix_with_post; \ _phoenix_with_post = false) // Small utilities for check pattern types. #define PHOENIX_IS_REF_IMPL_PHOENIX_REF(...) #define PHOENIX_IS_REF(ptn) PHOENIX_IS_EMPTY(PHOENIX_IS_REF_IMPL_ ## ptn) #define PHOENIX_IS_PTN_IMPL_PHOENIX_PTN(...) #define PHOENIX_IS_PTN(ptn) PHOENIX_IS_EMPTY(PHOENIX_IS_PTN_IMPL_ ## ptn) #define PHOENIX_IS_ANY_IMPL_ #define PHOENIX_IS_ANY(ptn) PHOENIX_IS_EMPTY(PHOENIX_IS_ANY_IMPL ## ptn) // Dispatching based on pattern type. #define PHOENIX_WITH_IMPL_1(ptn) PHOENIX_WITH_IMPL_PTN_1(ptn) #define PHOENIX_WITH_IMPL_2(ptn) PHOENIX_WITH_IMPL_PTN_2(ptn) #define PHOENIX_WITH_IMPL_3(ptn) PHOENIX_WITH_IMPL_PTN_3(ptn) #define PHOENIX_WITH_IMPL_4(ptn) PHOENIX_WITH_IMPL_PTN_4(ptn) #define PHOENIX_WITH_IMPL_5(ptn) PHOENIX_WITH_IMPL_PTN_5(ptn) #define PHOENIX_WITH_IMPL_PTN_1(ptn) \ PHOENIX_IF(PHOENIX_IS_PTN(ptn), \ PHOENIX_PTN_IMPL_1, PHOENIX_WITH_IMPL_REF)(ptn) #define PHOENIX_WITH_IMPL_PTN_2(ptn) \ PHOENIX_IF(PHOENIX_IS_PTN(ptn), \ PHOENIX_PTN_IMPL_2, PHOENIX_WITH_IMPL_REF)(ptn) #define PHOENIX_WITH_IMPL_PTN_3(ptn) \ PHOENIX_IF(PHOENIX_IS_PTN(ptn), \ PHOENIX_PTN_IMPL_3, PHOENIX_WITH_IMPL_REF)(ptn) #define PHOENIX_WITH_IMPL_PTN_4(ptn) \ PHOENIX_IF(PHOENIX_IS_PTN(ptn), \ PHOENIX_PTN_IMPL_4, PHOENIX_WITH_IMPL_REF)(ptn) #define PHOENIX_WITH_IMPL_PTN_5(ptn) \ PHOENIX_IF(PHOENIX_IS_PTN(ptn), \ PHOENIX_PTN_IMPL_5, PHOENIX_WITH_IMPL_REF)(ptn) #define PHOENIX_WITH_IMPL_REF(ptn) \ PHOENIX_IF(PHOENIX_IS_REF(ptn), PHOENIX_REF_IMPL, PHOENIX_WITH_IMPL_ANY)(ptn) #define PHOENIX_WITH_IMPL_ANY(ptn) \ PHOENIX_IF(PHOENIX_IS_ANY(ptn), PHOENIX_ANY_IMPL, PHOENIX_WITH_IMPL_VAL)(ptn) #define PHOENIX_WITH_IMPL_VAL(ptn) PHOENIX_VAL_IMPL(ptn) #define PHOENIX_CHECK_WITH_IMPL(macro) PHOENIX_CHECK_WITH_IMPL_I(macro(dummy)) #define PHOENIX_CHECK_WITH_IMPL_I(applied) PHOENIX_CHECK_WITH_IMPL_II(applied) #define PHOENIX_CHECK_WITH_IMPL_II(applied) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_CHECK_WITH_IMPL_ ## applied), 0, 1) #define PHOENIX_CHECK_WITH_IMPL_PHOENIX_WITH_IMPL_1(...) #define PHOENIX_CHECK_WITH_IMPL_PHOENIX_WITH_IMPL_2(...) #define PHOENIX_CHECK_WITH_IMPL_PHOENIX_WITH_IMPL_3(...) #define PHOENIX_CHECK_WITH_IMPL_PHOENIX_WITH_IMPL_4(...) #define PHOENIX_CHECK_WITH_IMPL_PHOENIX_WITH_IMPL_5(...) #define PHOENIX_WITH_IMPL PHOENIX_LOOKUP_UNUSED_WITH_IMPL_1() #define PHOENIX_LOOKUP_UNUSED_WITH_IMPL_1() \ PHOENIX_IF(PHOENIX_CHECK_WITH_IMPL(PHOENIX_WITH_IMPL_1), \ PHOENIX_WITH_IMPL_1, PHOENIX_LOOKUP_UNUSED_WITH_IMPL_2()) #define PHOENIX_LOOKUP_UNUSED_WITH_IMPL_2() \ PHOENIX_IF(PHOENIX_CHECK_WITH_IMPL(PHOENIX_WITH_IMPL_2), \ PHOENIX_WITH_IMPL_2, PHOENIX_LOOKUP_UNUSED_WITH_IMPL_3()) #define PHOENIX_LOOKUP_UNUSED_WITH_IMPL_3() \ PHOENIX_IF(PHOENIX_CHECK_WITH_IMPL(PHOENIX_WITH_IMPL_3), \ PHOENIX_WITH_IMPL_3, PHOENIX_LOOKUP_UNUSED_WITH_IMPL_4()) #define PHOENIX_LOOKUP_UNUSED_WITH_IMPL_4() \ PHOENIX_IF(PHOENIX_CHECK_WITH_IMPL(PHOENIX_WITH_IMPL_4), \ PHOENIX_WITH_IMPL_4, PHOENIX_LOOKUP_UNUSED_WITH_IMPL_5()) #define PHOENIX_LOOKUP_UNUSED_WITH_IMPL_5() \ PHOENIX_IF(PHOENIX_CHECK_WITH_IMPL(PHOENIX_WITH_IMPL_5), \ PHOENIX_WITH_IMPL_5, PHOENIX_TOO_DEEP_RECURSIVE PHOENIX_EAT) // Implement each pattern. #define PHOENIX_VAL_IMPL(val) if (!(*_phoenix_tmp.first == (val))) {} else #define PHOENIX_ANY_IMPL(val) #define PHOENIX_REF_IMPL(var) \ for (bool _phoenix_ref = true; _phoenix_ref; _phoenix_ref = false) \ for (const auto& PHOENIX_REF_ARG(var) = *_phoenix_tmp.first; \ _phoenix_ref; _phoenix_ref = false) #define PHOENIX_REF_ARG(var) PHOENIX_REF_ARG_IMPL_ ## var #define PHOENIX_REF_ARG_IMPL_PHOENIX_REF(var) var #define PHOENIX_IS_NIL_PHOENIX_NIL() #define PHOENIX_PTN_HEADER(typ) \ for (bool _phoenix_ptn = true; _phoenix_ptn; _phoenix_ptn = false) \ if (dynamic_cast<const typ*>(_phoenix_tmp.first) == 0) {} else #define PHOENIX_ARG_HEADER(idx, var, typ) \ for (bool var = true; var; var = false) \ for (const auto& _phoenix_expr = \ _phoenix_get ## idx(*static_cast<const typ*>(_phoenix_tmp.first)); \ var; var = false) \ for (const auto* _phoenix_old = &_phoenix_tmp; var; var = false) \ for (auto _phoenix_tmp = std::make_pair(&_phoenix_expr, _phoenix_old); \ var; var = false) #define PHOENIX_ARG_FOOTER(var) \ for (auto _phoenix_old = _phoenix_tmp.second; var; var = false) \ for (const auto& _phoenix_tmp = *_phoenix_old; var; var = false) #define PHOENIX_PTN_IMPL_1(ptn) \ PHOENIX_PTN_IMPL_1_I(PHOENIX_PTN_ARG_I_IMPL_1_ ## ptn) #define PHOENIX_PTN_IMPL_1_I(ptn) PHOENIX_PTN_IMPL_1_II ptn #define PHOENIX_PTN_IMPL_1_II(typ, args) \ PHOENIX_PTN_HEADER(typ) \ PHOENIX_ARG_EXPN_1(typ, PHOENIX_PTN_ARG_II_IMPL_1 args) #define PHOENIX_PTN_ARG_I_IMPL_1_PHOENIX_PTN(typ, args) (typ, args) #define PHOENIX_PTN_ARG_II_IMPL_1(...) __VA_ARGS__ #define PHOENIX_ARG_EXPN_1(...) PHOENIX_ARG_EXPN_1_I(__VA_ARGS__) #define PHOENIX_ARG_EXPN_1_I(...) \ PHOENIX_ARG_EXPN_1_0(__VA_ARGS__, PHOENIX_NIL, DUMMY) #define PHOENIX_ARG_EXPN_1_0(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_1(0, typ, arg) PHOENIX_ARG_EXPN_1_1) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_1_1(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_1(1, typ, arg) PHOENIX_ARG_EXPN_1_2) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_1_2(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_1(2, typ, arg) PHOENIX_ARG_EXPN_1_3) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_1_3(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_1(3, typ, arg) PHOENIX_ARG_EXPN_1_4) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_1_4(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_1(4, typ, arg) PHOENIX_ARG_EXPN_1_5) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_1_5(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, PHOENIX_TOO_MANY_ARGS PHOENIX_EAT) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_IMPL_1(idx, typ, arg) \ PHOENIX_ARG_HEADER(idx, _phoenix_arg_1, typ) \ PHOENIX_WITH_IMPL(arg) \ PHOENIX_ARG_FOOTER(_phoenix_arg_1) #define PHOENIX_PTN_IMPL_2(ptn) \ PHOENIX_PTN_IMPL_2_I(PHOENIX_PTN_ARG_I_IMPL_2_ ## ptn) #define PHOENIX_PTN_IMPL_2_I(ptn) PHOENIX_PTN_IMPL_2_II ptn #define PHOENIX_PTN_IMPL_2_II(typ, args) \ PHOENIX_PTN_HEADER(typ) \ PHOENIX_ARG_EXPN_2(typ, PHOENIX_PTN_ARG_II_IMPL_2 args) #define PHOENIX_PTN_ARG_I_IMPL_2_PHOENIX_PTN(typ, args) (typ, args) #define PHOENIX_PTN_ARG_II_IMPL_2(...) __VA_ARGS__ #define PHOENIX_ARG_EXPN_2(...) PHOENIX_ARG_EXPN_2_I(__VA_ARGS__) #define PHOENIX_ARG_EXPN_2_I(...) \ PHOENIX_ARG_EXPN_2_0(__VA_ARGS__, PHOENIX_NIL, DUMMY) #define PHOENIX_ARG_EXPN_2_0(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_2(0, typ, arg) PHOENIX_ARG_EXPN_2_1) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_2_1(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_2(1, typ, arg) PHOENIX_ARG_EXPN_2_2) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_2_2(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_2(2, typ, arg) PHOENIX_ARG_EXPN_2_3) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_2_3(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_2(3, typ, arg) PHOENIX_ARG_EXPN_2_4) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_2_4(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_2(4, typ, arg) PHOENIX_ARG_EXPN_2_5) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_2_5(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, PHOENIX_TOO_MANY_ARGS PHOENIX_EAT) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_IMPL_2(idx, typ, arg) \ PHOENIX_ARG_HEADER(idx, _phoenix_arg_2, typ) \ PHOENIX_WITH_IMPL(arg) \ PHOENIX_ARG_FOOTER(_phoenix_arg_2) #define PHOENIX_PTN_IMPL_3(ptn) \ PHOENIX_PTN_IMPL_3_I(PHOENIX_PTN_ARG_I_IMPL_3_ ## ptn) #define PHOENIX_PTN_IMPL_3_I(ptn) PHOENIX_PTN_IMPL_3_II ptn #define PHOENIX_PTN_IMPL_3_II(typ, args) \ PHOENIX_PTN_HEADER(typ) \ PHOENIX_ARG_EXPN_3(typ, PHOENIX_PTN_ARG_II_IMPL_3 args) #define PHOENIX_PTN_ARG_I_IMPL_3_PHOENIX_PTN(typ, args) (typ, args) #define PHOENIX_PTN_ARG_II_IMPL_3(...) __VA_ARGS__ #define PHOENIX_ARG_EXPN_3(...) PHOENIX_ARG_EXPN_3_I(__VA_ARGS__) #define PHOENIX_ARG_EXPN_3_I(...) \ PHOENIX_ARG_EXPN_3_0(__VA_ARGS__, PHOENIX_NIL, DUMMY) #define PHOENIX_ARG_EXPN_3_0(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_3(0, typ, arg) PHOENIX_ARG_EXPN_3_1) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_3_1(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_3(1, typ, arg) PHOENIX_ARG_EXPN_3_2) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_3_2(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_3(2, typ, arg) PHOENIX_ARG_EXPN_3_3) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_3_3(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_3(3, typ, arg) PHOENIX_ARG_EXPN_3_4) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_3_4(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_3(4, typ, arg) PHOENIX_ARG_EXPN_3_5) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_3_5(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, PHOENIX_TOO_MANY_ARGS PHOENIX_EAT) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_IMPL_3(idx, typ, arg) \ PHOENIX_ARG_HEADER(idx, _phoenix_arg_3, typ) \ PHOENIX_WITH_IMPL(arg) \ PHOENIX_ARG_FOOTER(_phoenix_arg_3) #define PHOENIX_PTN_IMPL_4(ptn) \ PHOENIX_PTN_IMPL_4_I(PHOENIX_PTN_ARG_I_IMPL_4_ ## ptn) #define PHOENIX_PTN_IMPL_4_I(ptn) PHOENIX_PTN_IMPL_4_II ptn #define PHOENIX_PTN_IMPL_4_II(typ, args) \ PHOENIX_PTN_HEADER(typ) \ PHOENIX_ARG_EXPN_4(typ, PHOENIX_PTN_ARG_II_IMPL_4 args) #define PHOENIX_PTN_ARG_I_IMPL_4_PHOENIX_PTN(typ, args) (typ, args) #define PHOENIX_PTN_ARG_II_IMPL_4(...) __VA_ARGS__ #define PHOENIX_ARG_EXPN_4(...) PHOENIX_ARG_EXPN_4_I(__VA_ARGS__) #define PHOENIX_ARG_EXPN_4_I(...) \ PHOENIX_ARG_EXPN_4_0(__VA_ARGS__, PHOENIX_NIL, DUMMY) #define PHOENIX_ARG_EXPN_4_0(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_4(0, typ, arg) PHOENIX_ARG_EXPN_4_1) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_4_1(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_4(1, typ, arg) PHOENIX_ARG_EXPN_4_2) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_4_2(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_4(2, typ, arg) PHOENIX_ARG_EXPN_4_3) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_4_3(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_4(3, typ, arg) PHOENIX_ARG_EXPN_4_4) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_4_4(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, \ PHOENIX_ARG_IMPL_4(4, typ, arg) PHOENIX_ARG_EXPN_4_5) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_EXPN_4_5(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg ()), \ PHOENIX_EAT, PHOENIX_TOO_MANY_ARGS PHOENIX_EAT) \ (typ, __VA_ARGS__) #define PHOENIX_ARG_IMPL_4(idx, typ, arg) \ PHOENIX_ARG_HEADER(idx, _phoenix_arg_4, typ) \ PHOENIX_WITH_IMPL(arg) \ PHOENIX_ARG_FOOTER(_phoenix_arg_4) // Declaration for pattern. #define PHOENIX_DECLARE_PATTERN_HELPER(...) __VA_ARGS__ #define PHOENIX_DECLARE_PATTERN(typ, args) \ PHOENIX_DECLARE_PATTERN_EXPN(typ, PHOENIX_DECLARE_PATTERN_HELPER args) #define PHOENIX_DECLARE_PATTERN_EXPN(...) \ PHOENIX_DECLARE_PATTERN_EXPN_I(__VA_ARGS__) #define PHOENIX_DECLARE_PATTERN_EXPN_I(...) \ PHOENIX_DECLARE_PATTERN_EXPN_0(__VA_ARGS__, PHOENIX_NIL, DUMMY) #define PHOENIX_DECLARE_PATTERN_EXPN_0(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg()), \ PHOENIX_EAT, \ PHOENIX_DECLARE_PATTERN_IMPL(0, typ, arg) \ PHOENIX_DECLARE_PATTERN_EXPN_1) (typ, __VA_ARGS__) #define PHOENIX_DECLARE_PATTERN_EXPN_1(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg()), \ PHOENIX_EAT, \ PHOENIX_DECLARE_PATTERN_IMPL(1, typ, arg) \ PHOENIX_DECLARE_PATTERN_EXPN_2) (typ, __VA_ARGS__) #define PHOENIX_DECLARE_PATTERN_EXPN_2(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg()), \ PHOENIX_EAT, \ PHOENIX_DECLARE_PATTERN_IMPL(2, typ, arg) \ PHOENIX_DECLARE_PATTERN_EXPN_3) (typ, __VA_ARGS__) #define PHOENIX_DECLARE_PATTERN_EXPN_3(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg()), \ PHOENIX_EAT, \ PHOENIX_DECLARE_PATTERN_IMPL(3, typ, arg) \ PHOENIX_DECLARE_PATTERN_EXPN_4) (typ, __VA_ARGS__) #define PHOENIX_DECLARE_PATTERN_EXPN_4(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg()), \ PHOENIX_EAT, \ PHOENIX_DECLARE_PATTERN_IMPL(4, typ, arg) \ PHOENIX_DECLARE_PATTERN_EXPN_5) (typ, __VA_ARGS__) #define PHOENIX_DECLARE_PATTERN_EXPN_5(typ, arg, ...) \ PHOENIX_IF(PHOENIX_IS_EMPTY(PHOENIX_IS_NIL_ ## arg()), \ PHOENIX_EAT, \ PHOENIX_TOO_MANY_ARGS PHOENIX_EAT) (typ, __VA_ARGS__) #define PHOENIX_DECLARE_PATTERN_IMPL(idx, typ, arg) \ auto _phoenix_get ## idx(const typ& val) -> decltype(val.arg) { \ return val.arg; \ } #endif // PHOENIX_PATTERN_H_
長い。。。
初プリプロセッサプログラミング。とりあえずg++4.4では動く様子。
g++ --std=gnu++0x test.cc
ちょこちょこバグにはまったし・・・。
もうちょっとシンプルになるときっと思う、が今はこれがいっぱいいっぱいっぽい。有識者求むw。
パターンの深さは5段まで、パターンの引数の数も5つまで。
バグ、動かない等ありそうですが、まぁご愛嬌で。
known issue:
- PHOENIX_PTN マクロの型に pair
とかいれるとたぶん動かない。 - __VA_ARGS__ 周りはもうちょっとシンプルになるはず。
- もうちょいいろいろ書けるように自由度増やしたいかも。
- 実用に耐えられそうにない。
- メンテしんどい
参考資料:
以下のに大変お世話になりました。
DigitalGhostさんの日記
tanakhさんのPFIセミナー資料
マクロ展開に関する資料