マクロの可変引数が空の場合の判定が結構面倒にょろ
カンマの数を数えるのは結構簡単なんですが空と一つを区別するには結構ややこしいことに気づいて誰かやってるだろうってことで検索なんかして見つけるわけなんですがその実装がややこしくもっと楽な実装あるんじゃないか考えてみました
参考 https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
自分はカンマ数えて 0 ならトークンくっつけてマクロ参照できれば空ってな感じにして見ました
#define HAS_COMMA(...) HAS_COMMA_(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) #define HAS_COMMA_(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,...) a19 #define JOIN2(x,y) JOIN2_(x,y) #define JOIN2_(x,y) x ## y #define JOIN3(x,y,z) JOIN3_(x,y,z) #define JOIN3_(x,y,z) x ## y ## z #define ISEMPTY(...) JOIN2(ISEMPTY0_, HAS_COMMA(__VA_ARGS__))(__VA_ARGS__) #define ISEMPTY0_1(...) 0 #define ISEMPTY0_0(...) HAS_COMMA(JOIN3(ISEMPTY1, __VA_ARGS__, _)) #define ISEMPTY1_ ,
テストは参考サイトの物を利用したんですが ISEMPTY( ( void ) ) の結果に違いが出ました、まあこの考慮はいらんでしょって思うことにして完成にしようと思うんですがどんなもんでしょうね~
BOOST_PP_BOOL が 256 までにょろ
プリプロセッサの常套手段としてルックアップテーブル的な実装で何でもこなしちゃうってのはまあ分かるんですが 有限なのはちょいと困るので 0 false !n true になるようなものを考えてみました
力技ならこんな感じ
#define BOOL(x) BOOL ## x #define BOOL0 0 #define BOOL1 1 // #define BOOLx 1
マクロ定義がマッチすればカンマを増やして 2 個目の引数で答えを返すようにしてやります
#define BOOL(x) BOOL1_(JOIN2(BOOL0_, x), 1, -1) #define BOOL0_0 -1, 0 #define BOOL1_(...) EXPAND(BOOL2_(__VA_ARGS__)) #define BOOL2_(x, y, ...) y #define JOIN2(x, y) JOIN2_(x, y) #define JOIN2_(x, y) x ## y #define EXPAND(...) EXPAND_(__VA_ARGS__) #define EXPAND_(...) __VA_ARGS__
負の数はたぶんマクロでがんばれないのでまあこんな感じなところですかね~
参考 http://stackoverflow.com/questions/319328/writing-a-while-loop-in-the-c-preprocessor
@deprecated 指定したけど気に掛けてくれないにょろ
sprintf は危険なことが多く使ってほしくないので doxygen のドキュメントとして使ってほしくないリストへ現れるようにこんな感じにしてたんですが
/// @deprecated #define sprintf sprintf
危険な関数を使ってしまう奴は doxygen 出力して把握してくれるわけでもなく告知もスルーするわけなんでそんな人のソースみて打ち震えるよりはコンパイラが文句を吐き出してしまうほうが確実なのでメッセージを出してやります
#pragma message "このだめ人間め"
これだけだと条件コンパイルぐらいでしか使えないのでこのヘッダ使うなとかこのマクロ定義されてないのでデフォルトにするよとかしか警告できないですよね
プログラマが関数を 使ったときに 何か文句を言ってあげる必要があるので機能を探してみたら C99 でプラグマがマクロで利用できるようになってたのを思い出しました
_Pragma("message \"このだめ人間め\"")
これを使ってマクロで警告できるようにして見ます
#define WERN(x) /**/ WERN_(message x) #define WERN_(x) /**/ _Pragma(#x) #define sprintf /**/ WERN("sprintf を使うだめ人間め") sprintf
これで sprintf を使うと文句をプログラマに見せることが可能になりました、あとは stdio.h よりあとに定義されるよう工夫すれば OK です、C言語系ぐらいでしか使い道が無いんですがまあ気休めにいかがでしょうか
フォーマットを扱うマクロを適切に使い分けてくれないにょろ
C言語で文字列を整形する為に printf 等を利用することが多いわけなんですが printf 的なものをマクロ LOGF(...) でくるむと文字列表示期待で LOGF("%s", "A") ではなく LOGF("A") としがちです、%が混じってなければ安全なんですがこのような形を続けられるといつの間にか % がフォーマット文字列に追加され引数が増えなことが多々有ります。 (多くは出力文字列が壊れる程度だけど制御コードが発動したり %n がきたりすると悲しい目に遭います)
人がやることなんで間違うのはしょうが無いということで F がフォーマット指定に見えないなら出来るだけ回避するように考えてみました。
まずはコンマがあるか調べるマクロを用意します
#define HAS_COMMA(...) HAS_COMMA_(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) #define HAS_COMMA_(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,...) a19
参考 https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
(ゲーム屋なので 4x4 以上にしました)
トークンを連結するマクロを用意します
#define JOIN(a, b) JOIN2(a, b) #define JOIN2(a, b) a ## b
あとはカンマが有ればマクロを切り替える感じで
#define LOG(...) JOIN(LOG_, HAS_COMMA(__VA_ARGS__))(__VA_ARGS__) #define LOG_0(str) printf("%s", str) #define LOG_1(...) printf(__VA_ARGS__)
期待通り展開されるか確認します
a.cpp
LOG("%s\n"); LOG("%s\n", "abc");
g++ -E a.cpp
printf("%s", "%s\n"); printf("%s\n", "abc");
これで文字列がフォーマットと解釈される危険が少なくなりましたよ~