ぼくのかんがえたさいきょうのぱたーんまっち。

以前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セミナー資料
マクロ展開に関する資料