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; }
自殺とか生命軽視な感じがして不謹慎です><;;;;;;;;;;
不快に思ったらごめんね。一応冗談のつもりでした。