(応答なし)

2008-02-25

[]NTPと型のアップキャスト

先日の記事(id:uruwasi:20080220:1203484601)で

“後はboost::is_base_ofを使ってNTP_REDECに入力する型を基底クラスにキャストする実装を書けばいいんだけれど”

型に対するキャストとはどう言う事だ

となじられるのも嫌なので、気力を++して書いてきました。主にtupleからsequenceへの移行、継承に関するものその他を無駄に思いつつ改良。

しかし、無責任にもboost::is_base_ofは使ってません。

簡単な例

#include <iostream>
using std::cout; using std::endl;

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

NTP(
  struct, test_2,
  ((int, V))
), test_1<char, char, 987, 789>{
  typedef test_1<char, char, 987, 789> base_1;
  void print_value(){ cout << V << endl; }
};

NTP(
  struct, test_3,
  ((typename, T))
), test_2<1024>{
  typedef test_2<1024> base_2;
  void print_typename(){ cout << typeid(T).name() << endl; }
};

int main(){
  typedef test_1<int, short, 123, 321> t1;
  { t1 a; a.f(); cout << endl; }

  typedef NTP_REDEC(test_1, t1)::T1<void>::V2<1>::end t2;
  { t2 a; a.f(); cout << endl; }

  typedef test_3<const void * const &> t3;
  {
    t3 a;
    a.print_typename();
    cout << endl;

    t3::base_1 *ptr1 = &a;
    ptr1->f();
    cout << endl;

    t3::base_2 *ptr2 = &a;
    ptr2->print_value();
    cout << endl;
  }

  // 型の'アップキャスト'
  // t3 は test_1 を継承した test_3 の typedef であって test_1 ではない
  typedef NTP_REDEC(test_1, t3)::T2<char********>::end t4;
  { t4 a; a.f(); cout << endl; }

  return 0;
}

結果

int
short
123
321

void
short
123
1

void const *

char
char
987
789

1024

char
char * * * * * * * *
987
789

実装

#include <boost/preprocessor.hpp>

#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_CLASS_WRITEARG_0_I(r, nil, i, tuple) \
  BOOST_PP_COMMA_IF(i) \
  BOOST_PP_TUPLE_ELEM(2, 0, tuple) \
  BOOST_PP_TUPLE_ELEM(2, 1, tuple)

#define NTP_CLASS_WRITEARG_0(seq) \
  BOOST_PP_SEQ_FOR_EACH_I(NTP_CLASS_WRITEARG_0_I, nil, seq)

#define NTP_ARG_WRITEARG_0_I(r, nil, i, tuple) \
  BOOST_PP_COMMA_IF(i) BOOST_PP_TUPLE_ELEM(2, 1, tuple)

#define NTP_ARG_WRITEARG_0(seq) \
  BOOST_PP_SEQ_FOR_EACH_I(NTP_ARG_WRITEARG_0_I, nil, seq)

// 引数名を連番で記述する 1
// targ_n
#define NTP_CLASS_WRITEARG_1_I(r, nil, i, tuple) \
  BOOST_PP_COMMA_IF(i) \
  BOOST_PP_TUPLE_ELEM(2, 0, tuple) \
  BOOST_PP_CAT(targ_, i)

#define NTP_CLASS_WRITEARG_1(seq) \
  BOOST_PP_SEQ_FOR_EACH_I(NTP_CLASS_WRITEARG_1_I, nil, seq)

#define NTP_ARG_WRITEARG_1_I(r, nil, i, tuple) \
  BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(targ_, i)

#define NTP_ARG_WRITEARG_1(seq) \
  BOOST_PP_SEQ_FOR_EACH_I(NTP_ARG_WRITEARG_1_I, nil, seq)

// 引数名を連番で記述する 2
// targ_n_
#define NTP_CLASS_WRITEARG_2_I(r, nil, i, tuple) \
  BOOST_PP_COMMA_IF(i) \
  BOOST_PP_TUPLE_ELEM(2, 0, tuple) \
  BOOST_PP_CAT(BOOST_PP_CAT(targ_, i), _)

#define NTP_CLASS_WRITEARG_2(seq) \
  BOOST_PP_SEQ_FOR_EACH_I(NTP_CLASS_WRITEARG_2_I, nil, seq)

#define NTP_ARG_WRITEARG_2_I(r, nil, i, tuple) \
  BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(BOOST_PP_CAT(targ_, i), _)

#define NTP_ARG_WRITEARG_2(seq) \
  BOOST_PP_SEQ_FOR_EACH_I(NTP_ARG_WRITEARG_2_I, nil, seq)

//
#define NTP_ARGSTRUCT_III() _

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

#define NTP_ARGSTRUCT_I(z, i, spi) \
  BOOST_PP_COMMA_IF(i) \
  BOOST_PP_CAT(BOOST_PP_CAT(targ_, i), NTP_ARGSTRUCT_II(i, spi))

#define NTP_ARGSTRUCT(r, seq, i, tuple) \
  template< \
    BOOST_PP_TUPLE_ELEM(2, 0, tuple) \
    BOOST_PP_CAT(BOOST_PP_CAT(targ_, i), _) \
  > struct BOOST_PP_TUPLE_ELEM(2, 1, tuple) : \
    dg<BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(seq), NTP_ARGSTRUCT_I, i)>{};

#define NTP_THIS_TYPE_HOLDER(name) \
  BOOST_PP_CAT(this_t_holder_, BOOST_PP_CAT(name, __))

#define NTP_THIS_TYPE(name) \
  BOOST_PP_CAT(BOOST_PP_CAT(_, name), _this_t__)

#define NTP_REDECDG(name) \
  BOOST_PP_CAT(BOOST_PP_CAT(_, name), _recdg__)

#define NTP_REDEC__(name) \
  BOOST_PP_CAT(BOOST_PP_CAT(_, name), _redec__)

#define NTP_HEAD(dec, name, seq) \
  template<NTP_CLASS_WRITEARG_0(seq)> dec name; \
  template<NTP_CLASS_WRITEARG_1(seq)> struct NTP_THIS_TYPE_HOLDER(name) \
  { typedef name<NTP_ARG_WRITEARG_1(seq)> NTP_THIS_TYPE(name); }; \
  namespace{ \
    template<NTP_CLASS_WRITEARG_1(seq)> struct NTP_REDECDG(name){ \
      template<NTP_CLASS_WRITEARG_2(seq)> struct holder \
      { typedef name<NTP_ARG_WRITEARG_2(seq)> end; }; \
      template<NTP_CLASS_WRITEARG_2(seq)> struct dg : \
        holder<NTP_ARG_WRITEARG_2(seq)>, \
        NTP_REDECDG(name)<NTP_ARG_WRITEARG_2(seq)>{}; \
      BOOST_PP_SEQ_FOR_EACH_I(NTP_ARGSTRUCT, seq, seq) \
    };\
    template<typename T> struct BOOST_PP_CAT(BOOST_PP_CAT(_, name), _redec__); \
    template<NTP_CLASS_WRITEARG_1(seq)> \
    struct NTP_REDEC__(name)< name<NTP_ARG_WRITEARG_1(seq)> > : \
      BOOST_PP_CAT(BOOST_PP_CAT(_, name), _recdg__)<NTP_ARG_WRITEARG_1(seq)>{}; \
  }

#define NTP_DEC(dec, name, seq) \
  template<NTP_CLASS_WRITEARG_0(seq)> dec name : \
  public NTP_THIS_TYPE_HOLDER(name)<NTP_ARG_WRITEARG_0(seq)>

#define NTP(dec, name, seq) \
  NTP_HEAD(dec, name, seq) NTP_DEC(dec, name, seq)

#define NTP_REDEC(target, type) NTP_REDEC__(target)<type::NTP_THIS_TYPE(target)>

コメントへのレス

boost/parameter/aux_/preprocessor/for_each.hppは後で読みます。保留。

2008-02-20

[]

C++をやる前に英語を勉強した方がいいんじゃ・・・。

[]

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のような便利なものがあったならもっと遅く書き始めていれば良かった・・・。あの時の自分の衝動を呪う。

2008-02-19

[][]難しく考え過ぎでした

redecで再設定するクラスターゲットを指定すれば良いだけの話。多分これで継承問題を解決できると思います。思うだけです。知りません。

勢いで書いたので、冗長な部分とかあったら添削とかツッコミとか可。

楽しみに待っててね!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

マクロのインターフェイスとか(予定)

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

元となる考え(これをマクロで自動生成する方法を考える)

template<typename T1, typename T2, int V1> struct test;

template<typename targ_0, typename targ_1, int targ_2> struct _test_recdg__
{
  template<typename targ_0_, typename targ_1_, int targ_2_> struct holder{
    typedef test<targ_0_, targ_1_, targ_2_> end;
  };

  template<typename targ_0_, typename targ_1_, int targ_2_> struct dg :
    holder<targ_0_, targ_1_, targ_2_>,
    _test_recdg__<targ_0_, targ_1_, targ_2_>
  {};

  template<typename targ_0_> struct T1 :
    dg<targ_0_, targ_1, targ_2>
  {};

  template<typename targ_1_> struct T2 :
    dg<targ_0, targ_1_, targ_2>
  {};

  template<int targ_2_> struct V1 :
    dg<targ_0, targ_1, targ_2_>
  {};
};

template<typename T> struct _test_redec__;
template<typename targ_0, typename targ_1, int targ_2> struct _test_redec__< test<targ_0, targ_1, targ_2> > :
  _test_recdg__<targ_0, targ_1, targ_2>
{};

template<typename T1, typename T2, int V1> struct test
{
  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; }
};

#define redec(target, type) _##target##_redec__<type>

int main(){
  typedef test<void, void, 128> type1;
  type1 a;

  std::cout << "----- type1" << std::endl;
  a.t1();
  a.t2();
  a.v1();

  typedef redec(test, type1)::T1<int>::T2<short>::V1<256>::end type2;
  type2 b;

  std::cout << std::endl << "----- type2" << std::endl;
  b.t1();
  b.t2();
  b.v1();

  return 0;
}

[][]思ったよりも苦戦しております

継承問題を解決するNTP生成マクロが難しい。

まず、引数再設定を行うクラスの中に「再設定を明示する何か」(redec)を入れることはボツ。昨日の様に、同じNTP生成マクロで生成したクラスを継承すると基底のものか派生のものかで曖昧になるからですううう。

それでredecを外の空間に追いやってしまう。将来的には

redec<type>::arg1<hogehoge>::arg2<fugafuga>::end;

でどうにかする予定。

そして次に、外にあるredecがどうやって引数名を取得して再設定用の構造体を作るか。これは、マクロの段階でint2typeとか継承とかを使って、裏でredecに渡す方法を考える予定。いや、本当は分からん。だって継承したらそれこそ曖昧になるじゃないか。

『派生クラスにはprivateだけどいつもはpublicなアクセス指定子』みたいなのがほしいいいいいい。なんかこういう事ずっと前にも考えてた様な気がする。多分思いついたのはC++学びたての頃だったな。protectedを見た後、『これとは逆に(上にある様な)指定子もいつかは必要になるかもしれないなフヒヒ』なんて思いを巡らせた青春(にしても悲しい青春だ)。それが現実になるとは。

[][]

先日のNTPなクラスを簡単に定義するマクロid:uruwasi:20080217:1203225365)を力作業でないもの、例えばBOOST_PP_REPEATなどを使って書こうと思う。近々。

name_rec__::redec内の、再設定するテンプレート引数を受け取り再設定するもの以外の引数を既存のもので維持する構造体が結構ややこしい、というか綺麗に書けなくて泣ける。boost.ppに関する記事boostをもう1年くらいも前から知っておきながら最近知った。勉強します。

後は、NTP_Nマクロを使って定義したものが更にNTP_Nマクロを使って定義された別のものか既に内部でクラスredecが存在するものを継承すると、トップレベルのクラスの引数だけをredecで変更しようと思ってもredecがどのクラスのものなのかが曖昧になってコンパイルエラーを招いていしまう。そこも何とか直しておこうと。新しいマクロを使って。はい。

しどろもどろなのは何もここに今書いている文だけじゃない、動きが、態度が、全てがおかしい。死にたい。これが噂のテクノストレスというものか。早く寝ないと。自殺自殺自殺

2008-02-17

[][]NTPなクラスを簡単に定義するマクロ

追記:いろいろと突っ込みどころが・・・

追記:
おかしい点だと思われる、NTP_N.hppの全体の行数NTP_32.hppの説明ヘッダを生成するコードを修正。
ヘッダを生成するコードの汚さは未だ修正されず・・・。

自殺したんじゃないの?

boostのソースを読んでいたら自分は書く事よりも読む事に専念した方が良いんじゃないかと思ってもうこのブログを書く事も止めてしまおうという意気込みで先日のエントリを書いたんですが、そんな風に思った矢先にNTP(名前付きテンプレート引数(ようやく再帰bindというスッキリしない呼び方から脱皮する事ができた(でもboostと関連付けられたNTPの話題とか見てると未だに無駄な努力という様な感じや似非NTPなんじゃないかという疑問も残る)))を簡単に実装するマクロを思いついたので、いつもの自己顕示欲に駆られてやっぱりここに公開しようかと思います。

ただboostが使えない環境での利用という若干滅茶苦茶な前提で作ったので、マクロ定義が力作業という問題点も残っています。

自分でNTPについて調べているという人や、boostが使えて当たり前な環境で作業をしている人は見ない方が良いかも知れません。

簡単な使い方

再帰bind(笑)と殆ど同じ。

#include <iostream>
#include "NTP_32.hpp" // このヘッダの説明は後ほど

// struct test を定義する.
// test<typename T, int Value1, int Value2> と大体同じ感じで.
NTP_3(
  struct, test,
  typename, T,
  int, Value1,
  int, Value2
){
  typedef test<T, Value1, Value2> this_t;
  typedef T type;
  void out1()const{ std::cout << "v1 " << Value1 << std::endl; }
  void out2()const{ std::cout << "v2 " << Value2 << std::endl; }
};

int main(){
  // 普通に使う分には typedef した方が無難.
  typedef test<int ,256, 1024> type1;
  type1 a;
  a.out1(), a.out2();

  // redec から, マクロで定義した名前でパラメータを連続で変更可能.
  // 気が済むまで変更したら最後に end を付けるのを忘れないで.
  typedef type1::redec::Value1<512>::Value2<2048>::end type2;
  type2 b;
  b.out1(), b.out2();

  return 0;
}

肝心のNTP_32.hppについてのsetumei

ヘッダの中身はこうなってます。

#ifndef NTP_HPP_
#define NTP_HPP_

#define NTP_1( \
    dec, \
    name, \
 dec_0, arg_0 \
  ) \
  template< \
 dec_0 arg_0 \
  > dec name; \
  template< \
 dec_0 arg_0##_arg \
  > struct name##_rec__{ \
    struct redec{ \
      template< \
 dec_0 arg_0##_arg_ \
      > struct inner{ \
        typedef name< \
 arg_0##_arg_ \
        > end; \
      }; \
      template< \
        dec_0 arg_0##_arg_ \
      > struct arg_0 : inner< \
        arg_0##_arg_ \
      >, name##_rec__< \
        arg_0##_arg_ \
      >::redec{}; \
    }; \
  }; \
  template< \
 dec_0 arg_0 \
  > dec name : public name##_rec__< \
 arg_0 \
  >

#define NTP_2( \
    dec, \
    name, \
 dec_0, arg_0, \
 dec_1, arg_1 \
  ) \
  template< \
 dec_0 arg_0, \
 dec_1 arg_1 \
  > dec name; \
  template< \
 dec_0 arg_0##_arg, \
 dec_1 arg_1##_arg \
  > struct name##_rec__{ \
    struct redec{ \
      template< \
 dec_0 arg_0##_arg_, \
 dec_1 arg_1##_arg_ \
      > struct inner{ \
        typedef name< \
 arg_0##_arg_, \
 arg_1##_arg_ \
        > end; \
      }; \
      template< \
        dec_0 arg_0##_arg_ \
      > struct arg_0 : inner< \
        arg_0##_arg_, \
        arg_1##_arg \
      >, name##_rec__< \
        arg_0##_arg_, \
        arg_1##_arg \
      >::redec{}; \
      template< \
        dec_1 arg_1##_arg_ \
      > struct arg_1 : inner< \
        arg_0##_arg, \
        arg_1##_arg_ \
      >, name##_rec__< \
        arg_0##_arg, \
        arg_1##_arg_ \
      >::redec{}; \
    }; \
  }; \
  template< \
 dec_0 arg_0, \
 dec_1 arg_1 \
  > dec name : public name##_rec__< \
 arg_0, \
 arg_1 \
  >

#define NTP_3( \
    dec, \
    name, \
 dec_0, arg_0, \
 dec_1, arg_1, \
 dec_2, arg_2 \
  ) \
  template< \
 dec_0 arg_0, \
 dec_1 arg_1, \
 dec_2 arg_2 \
  > dec name; \
  template< \
 dec_0 arg_0##_arg, \
 dec_1 arg_1##_arg, \
 dec_2 arg_2##_arg \
  > struct name##_rec__{ \
    struct redec{ \
      template< \
 dec_0 arg_0##_arg_, \
 dec_1 arg_1##_arg_, \
 dec_2 arg_2##_arg_ \
      > struct inner{ \
        typedef name< \
 arg_0##_arg_, \
 arg_1##_arg_, \
 arg_2##_arg_ \
        > end; \
      }; \
      template< \
        dec_0 arg_0##_arg_ \
      > struct arg_0 : inner< \
        arg_0##_arg_, \
        arg_1##_arg, \
        arg_2##_arg \
      >, name##_rec__< \
        arg_0##_arg_, \
        arg_1##_arg, \
        arg_2##_arg \
      >::redec{}; \
      template< \
        dec_1 arg_1##_arg_ \
      > struct arg_1 : inner< \
        arg_0##_arg, \
        arg_1##_arg_, \
        arg_2##_arg \
      >, name##_rec__< \
        arg_0##_arg, \
        arg_1##_arg_, \
        arg_2##_arg \
      >::redec{}; \
      template< \
        dec_2 arg_2##_arg_ \
      > struct arg_2 : inner< \
        arg_0##_arg, \
        arg_1##_arg, \
        arg_2##_arg_ \
      >, name##_rec__< \
        arg_0##_arg, \
        arg_1##_arg, \
        arg_2##_arg_ \
      >::redec{}; \
    }; \
  }; \
  template< \
 dec_0 arg_0, \
 dec_1 arg_1, \
 dec_2 arg_2 \
  > dec name : public name##_rec__< \
 arg_0, \
 arg_1, \
 arg_2 \
  >

// :
// :
// NTP_32まで

#endif

つまりNTP_Nマクロで宣言/定義したクラスは裏でname_rec__を継承しています(ほとんどモラル(笑)の問題ですが、name_rec__をユーザが使用できないように、わざと__を後ろにつけています)。

name_rec__はクラスredecを内部に持っていて、その中に定義されているテンプレート引数と同名のテンプレートクラスでパラメータを再設定できます。

NTP_N.hppヘッダを生成するコード

とても汚いです。「トークンの名前が気に入らねぇ!」って人はこれを変更して自分で自分だけのヘッダを出力してください。

ただし、NTP_Nマクロの行数は 2N^2 + 12N + 20 、NTP_N.hppヘッダ全体の行数は (2N^3 + 21N^2 + 79N) / 3 ととても膨大なものになるので、必要がない限り無闇に大きくしない方がいいです。

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

std::string int2str(const int &a){
  std::stringstream transfar;
  transfar << a;
  return transfar.str();
}

void create_hpp(){
  using std::endl; using std::string;

  static const int createnum = 32;
  static const string filename = string("NTP_") + int2str(createnum);


  std::fstream file_enable(
    (filename + string(".hpp")).c_str(),
    std::ios::out
  );

  file_enable << "#ifndef NTP_HPP_" << endl << "#define NTP_HPP_" << endl;

  static const int strnum = 6;
  string str[strnum], tmpstr;

  for(int i = 0; i < createnum; i++){
    file_enable << endl;

    for(int j = 0; j < strnum; j++) str[j].clear();
    str[0] += " dec_0, arg_0";
    str[1] += " dec_0 arg_0";
    str[2] += " dec_0 arg_0##_arg";
    str[3] += " dec_0 arg_0##_arg_";
    str[4] += " arg_0##_arg_";
    str[5] += " arg_0";
    for(int j = 1; j < (i + 1); j++){
      tmpstr = int2str(j);
      str[0] = str[0]
        + ", \\" + "\n"
        + " dec_" + tmpstr + ", arg_" + tmpstr;

      str[1] = str[1]
        + ", \\" + "\n"
        + " dec_" + tmpstr + " arg_" + tmpstr;

      str[2] = str[2]
        + ", \\" + "\n"
        + " dec_" + tmpstr + " arg_" + tmpstr + "##_arg";

      str[3] = str[3]
        + ", \\" + "\n"
        + " dec_" + tmpstr + " arg_" + tmpstr + "##_arg_";

      str[4] = str[4]
        + ", \\" + "\n"
        + " arg_" + tmpstr + "##_arg_";

      str[5] = str[5]
        + ", \\" + "\n"
        + " arg_" + tmpstr;
    }
    for(int j = 0; j < strnum; j++) str[j] = str[j] + " \\" + "\n";

    file_enable
      << "#define NTP_" << (i + 1) << "( \\" << endl
      << "    dec, \\" << endl
      << "    name, \\" << endl
      << str[0]
      << "  ) \\" << endl
      << "  template< \\" << endl
      << str[1]
      << "  > dec name; \\" << endl
      << "  template< \\" << endl
      << str[2]
      << "  > struct name##_rec__{ \\" << endl
      << "    struct redec{ \\" << endl
      << "      template< \\" << endl
      << str[3]
      << "      > struct inner{ \\" << endl
      << "        typedef name< \\" << endl
      << str[4]
      << "        > end; \\" << endl
      << "      }; \\" << endl;

      for(int j = 0; j < (i + 1); j++){
        tmpstr.clear();
        for(int k = 0; k < (i + 1); k++){
          tmpstr = tmpstr
            + "        arg_" + int2str(k) + (j == k ? "##_arg_, \\" : "##_arg, \\");

          if((k + 1) == (i + 1)){
            tmpstr.resize(tmpstr.size() - 3);
            tmpstr += " \\";
          }
          tmpstr += "\n";
        }

        file_enable
          << "      template< \\" << endl
          << "        dec_" << j << " arg_" << j << "##_arg_ \\" << endl
          << "      > struct arg_" << j << " : inner< \\" << endl
          << tmpstr
          << "      >, name##_rec__< \\" << endl
          << tmpstr
          << "      >::redec{}; \\" << endl;
      }

    file_enable
      << "    }; \\" << endl
      << "  }; \\" << endl
      << "  template< \\" << endl
      << str[1]
      << "  > dec name : public name##_rec__< \\" << endl
      << str[5]
      << "  >" << endl;
  }

  file_enable << "#endif" << endl;

  std::fstream file_disable(
    (filename + string("_disable") + string(".hpp")).c_str(),
    std::ios::out
  );

  file_disable << "#ifdef NTP_HPP_" << endl << "#undef NTP_HPP_" << endl;

  for(int i = 1; i <= createnum; i++){
    file_disable << "#undef NTP_" << i << endl;
  }

  file_disable << "#endif" << endl;
}

int main(){
  create_hpp();

  return 0;
}

自殺とか生命軽視な感じがして不謹慎です><;;;;;;;;;;

不快に思ったらごめんね。一応冗談のつもりでした。

2008-02-15

[]

C++が凄すぎるので自殺します。

2008-02-11

[]箱男の激短感想

ドグラマグラみたいに読む度に違った風に捉えることができて面白い」っていってしまうと読解力の不安定さが強調されてしまう感じでアレなんだけど、どうしても作品全体が読み手に対する形而上的な問いかけの媒体としてある様に思えてしまう。勿論、その作品単体も面白い。あとエロいので注意が必要。幸い(?)今流行のオタクにウケそうなエロさではないので全て去勢された視点で読む事ができたけど、やはりどうもこれの良さが分からない。グロテスク。

あと昨日のエントリにコメント書いてくれた人ありがとうございました。既にオナニーブログを見てくれている事に対するお礼を先行しているにもかかわらず、本当に反応があるなんて思わなかった。