NTPのマクロの中途半端な実装

後はboost::is_base_ofを使ってNTP_REDECに入力する型を基底クラスにキャストする実装を書けばいいんだけれど、下にある通り衝撃的な情報を入手したので書く気力が消滅。

#include <boost/preprocessor.hpp>
#include <boost/type_traits.hpp>
#include <iostream>

#define NTP_TUPLE_ARGTYPE(num, i, tuple) \
  BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_TUPLE_ELEM(num, i, tuple))

#define NTP_TUPLE_ARGNAME(num, i, tuple) \
  BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_TUPLE_ELEM(num, i, tuple))

#define NTP_TUPLE2_ARGTYPE(i, tuple2) \
  BOOST_PP_TUPLE_ELEM( \
    2, \
    0, \
    BOOST_PP_TUPLE_ELEM( \
      BOOST_PP_TUPLE_ELEM(2, 0, tuple2), \
      i, \
      BOOST_PP_TUPLE_ELEM(2, 1, tuple2) \
    ) \
  )

#define NTP_TUPLE2_ARGNAME(i, tuple2) \
  BOOST_PP_TUPLE_ELEM( \
    2, \
    1, \
    BOOST_PP_TUPLE_ELEM( \
      BOOST_PP_TUPLE_ELEM(2, 0, tuple2), \
      i, \
      BOOST_PP_TUPLE_ELEM(2, 1, tuple2) \
    ) \
  )

// 引数名をtupleから取ってくる
#define NTP_CLASS_WRITEARG_0_I(z, i, tuple2) \
  NTP_TUPLE2_ARGTYPE(i, tuple2) NTP_TUPLE2_ARGNAME(i, tuple2),

#define NTP_CLASS_WRITEARG_0(num, tuple) \
  BOOST_PP_REPEAT(BOOST_PP_SUB(num, 1), NTP_CLASS_WRITEARG_0_I, (num, tuple)) \
  NTP_TUPLE_ARGTYPE(num, BOOST_PP_SUB(num, 1), tuple) \
  NTP_TUPLE_ARGNAME(num, BOOST_PP_SUB(num, 1), tuple)

#define NTP_ARG_WRITEARG_0_I(z, i, tuple2) \
  NTP_TUPLE2_ARGTYPE(i, tuple2),

#define NTP_ARG_WRITEARG_0(num, tuple) \
  BOOST_PP_REPEAT(BOOST_PP_SUB(num, 1), NTP_ARG_WRITEARG_0_I, (num, tuple)) \
  NTP_TUPLE_ARGNAME(num, BOOST_PP_SUB(num, 1), tuple)

// 引数名を連番で記述する 1
// targ_n
#define NTP_CLASS_WRITEARG_1_I(z, i, tuple2) \
  NTP_TUPLE2_ARGTYPE(i, tuple2) BOOST_PP_CAT(targ_, i),

#define NTP_CLASS_WRITEARG_1(num, tuple) \
  BOOST_PP_REPEAT(BOOST_PP_SUB(num, 1), NTP_CLASS_WRITEARG_1_I, (num, tuple)) \
  NTP_TUPLE_ARGTYPE(num, BOOST_PP_SUB(num, 1), tuple) \
  BOOST_PP_CAT(targ_, BOOST_PP_SUB(num, 1))

#define NTP_ARG_WRITEARG_1_I(z, i, tuple2) \
  BOOST_PP_CAT(targ_, i),

#define NTP_ARG_WRITEARG_1(num, tuple) \
  BOOST_PP_REPEAT(BOOST_PP_SUB(num, 1), NTP_ARG_WRITEARG_1_I, (num, tuple)) \
  BOOST_PP_CAT(targ_, BOOST_PP_SUB(num, 1))

// 引数名を連番で記述する 2
// targ_n_
#define NTP_CLASS_WRITEARG_2_I(z, i, tuple2) \
  NTP_TUPLE2_ARGTYPE(i, tuple2) BOOST_PP_CAT(BOOST_PP_CAT(targ_, i), _),

#define NTP_CLASS_WRITEARG_2(num, tuple) \
  BOOST_PP_REPEAT(BOOST_PP_SUB(num, 1), NTP_CLASS_WRITEARG_2_I, (num, tuple)) \
  BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_TUPLE_ELEM(num, BOOST_PP_SUB(num, 1), tuple)) \
  BOOST_PP_CAT(BOOST_PP_CAT(targ_, BOOST_PP_SUB(num, 1)), _)

#define NTP_ARG_WRITEARG_2_I(z, i, tuple2) \
  BOOST_PP_CAT(BOOST_PP_CAT(targ_, i), _),

#define NTP_ARG_WRITEARG_2(num, tuple) \
  BOOST_PP_REPEAT(BOOST_PP_SUB(num, 1), NTP_ARG_WRITEARG_2_I, (num, tuple)) \
  BOOST_PP_CAT(BOOST_PP_CAT(targ_, BOOST_PP_SUB(num, 1)), _)

//
#define NTP_ARGSTRUCT_II() _

#define NTP_ARGSTRUCT_I_II(i, spi) \
  BOOST_PP_IIF(BOOST_PP_EQUAL(i, spi), NTP_ARGSTRUCT_II, BOOST_PP_EMPTY)()

#define NTP_ARGSTRUCT_I_I(i, spi) \
  BOOST_PP_CAT(BOOST_PP_CAT(targ_, i), NTP_ARGSTRUCT_I_II(i, spi))

#define NTP_ARGSTRUCT_I(z, i, spi) \
  NTP_ARGSTRUCT_I_I(i, spi),

#define NTP_ARGSTRUCT(z, i, tuple2) \
  template< \
    NTP_TUPLE2_ARGTYPE(i, tuple2) BOOST_PP_CAT(BOOST_PP_CAT(targ_, i), _) \
  > \
  struct NTP_TUPLE2_ARGNAME(i, tuple2) : \
    dg< \
      BOOST_PP_REPEAT(BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(2, 0, tuple2), 1), NTP_ARGSTRUCT_I, i) \
      NTP_ARGSTRUCT_I_I(BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(2, 0, tuple2), 1), i) \
    >{};

// ヘッダの生成
// このマクロでヘッダさえ作れば
// クラス宣言は別の部分で化膿
#define NTP_HEAD(dec, name, num, tuple) \
  template<NTP_CLASS_WRITEARG_0(num, tuple)> dec name; \
  namespace{ \
    template<NTP_CLASS_WRITEARG_1(num, tuple)> struct BOOST_PP_CAT(BOOST_PP_CAT(_, name), _recdg__){ \
      template<NTP_CLASS_WRITEARG_2(num, tuple)> struct holder \
      { typedef name<NTP_ARG_WRITEARG_2(num, tuple)> end; }; \
      template<NTP_CLASS_WRITEARG_2(num, tuple)> struct dg : \
        holder<NTP_ARG_WRITEARG_2(num, tuple)>, \
        BOOST_PP_CAT(BOOST_PP_CAT(_, name), _recdg__)<NTP_ARG_WRITEARG_2(num, tuple)>{}; \
      BOOST_PP_REPEAT(num, NTP_ARGSTRUCT, (num, tuple)) \
    };\
    template<typename T> struct BOOST_PP_CAT(BOOST_PP_CAT(_, name), _redec__); \
    template<NTP_CLASS_WRITEARG_1(num, tuple)> struct BOOST_PP_CAT(BOOST_PP_CAT(_, name), _redec__)< name<NTP_ARG_WRITEARG_1(num, tuple)> > : \
      BOOST_PP_CAT(BOOST_PP_CAT(_, name), _recdg__)<NTP_ARG_WRITEARG_1(num, tuple)>{}; \
  }

#define NTP(dec, name, num, tuple) \
  NTP_HEAD(dec, name, num, tuple) \
  template<NTP_CLASS_WRITEARG_0(num, tuple)> dec name

#define NTP_REDEC(target, type) BOOST_PP_CAT(BOOST_PP_CAT(_, target), _redec__)<type>

NTP(
  struct, test_1, 4,
  (
    (typename, T1),
    (typename, T2),
    (int, V1),
    (int, V2)
  )
){
  void t1(){ std::cout << typeid(T1).name() << std::endl; }
  void t2(){ std::cout << typeid(T2).name() << std::endl; }
  void v1(){ std::cout << V1 << std::endl; }
  void v2(){ std::cout << V2 << std::endl; }
};

NTP(
  struct, test_2, 2,
  (
    (typename, T1),
    (typename, T2)
  )
){
  T1 f1(T1 a){ return a * a; }  
  T2 f2(T2 a){ return a * a + a; }  
};

typedef test_1<void*, void**, 10, 20> tes1;
typedef test_2<int, double> tes2;

NTP(
  struct, test_3, 2,
  (
    (int, V1),
    (int, V2)
  )
) :
  // 他のNTPクラスも継承可能.
  tes1, tes2
{
  void f(){
    std::cout
      << "V1 " << V1 << ", V2 " << V2 << std::endl;

    tes1 *p1 = static_cast<tes1*>(this);
    p1->t1(); p1->t2(); p1->v1(); p1->v2();

    tes2 *p2 = static_cast<tes2*>(this);
    std::cout
      << p2->f1(16) << ", " << p2->f2(32.0) << std::endl;
  }
};

int main(){
  typedef test_1<int, short, 0, 1> type1;
  {
    type1 a;
    std::cout << "----- type1" << std::endl;
    a.t1(); a.t2(); a.v1(); a.v2();
  }

  std::cout << std::endl;

  // NTP_REDECで引数を再設定する.
  typedef NTP_REDEC(test_1, type1)::T1<int*>::T2<short*>::V1<2>::V2<3>::end type2;
  {
    type2 a;
    std::cout << "----- type2" << std::endl;
    a.t1(); a.t2(); a.v1(); a.v2();
  }

  std::cout << std::endl;

  // 継承を行ったクラスも使用可能.
  typedef test_3<64, 128> type3;
  {
    type3 a;
    std::cout << "----- type3" << std::endl;
    a.f();
  }

  std::cout << std::endl;

  typedef NTP_REDEC(test_3, type3)::V1<16>::V2<32>::end type4;
  {
    type4 a;
    std::cout << "----- type4" << std::endl;
    a.f();
  }

  return 0;
}

コメントに対するレス

uskz 2008/02/20 13:49 sequenceを使って

NTP(
 struct, test,
 ((typename, T1))
 ((typename, T2))
 ((int, V1))
)

の方がシンプルかもしれません
(そういえばBoost.PreprocessorにNTPサポートが)

BOOST_PP_TUPLE_ELEMでガリガリ書き終えたあとにそんな情報が・・・。それ以前に既にNTPのサポートがあったなんて・・・。
車輪の再発明はコーディングの練習という言い訳にはなるものの、boost.preprocessor.seqのような便利なものがあったならもっと遅く書き始めていれば良かった・・・。あの時の自分の衝動を呪う。