プリプロセッサで代入しましょう!
さて今回は代入です。とはいっても関数マクロを展開中に代入とかは無理です。なので、#defineで、プリプロセスシンボルに代入しましょう。
あともうかなりめんどいので超展開で話が進みます。
#define A 1 #define B A #undef A #define A 2 B
最後の行のBは、もちろん2になります。Bが展開されてAになり、Aが展開されて2になります。Bが定義されたときのAの定義なんて知ったこっちゃありません。Bを展開しようとしたときの定義が重要です。
しかし私はBを展開すると1になるようにしたいのです。なんで?世の中には大きく分けて二つの行動があります。理由のある行動と、ない行動。そしてこれは後者のほうだ。
#define A 1 #define PP_SLOT A #include "pp_slot.hpp" #undef #define A 2 PP_HOLDER
なんとPP_HOLDERは1と展開されます。ってPP_HOLDERって何ですか?答えはpp_slot.hppの中にあります。これです。
#undef PP_HOLDER #if PP_SLOT == 0 # define PP_HOLDER 0 #elif PP_SLOT == 1 # define PP_HOLDER 1 #elif PP_SLOT == 2 # define PP_HOLDER 2 #elif PP_SLOT == 3 # define PP_HOLDER 3 ... #endif #undef PP_SLOT
こうしておけば、PP_SLOTの定義が変更されても、pp_slot.hppがインクルードされた時点でのPP_SLOTの定義でPP_HOLDERの定義が決まります。単純!
まぁ任意のトークンでこれができるわけではありません。あくまでも数値限定ですね。あと、PP_HOLDERとPP_SLOTはいい感じの位置でundefしておきます。「再定義してるで」的な警告とかやかましいので。
で、ただの代入だけじゃなくて、こんなこともできるわけです。
#define A 1 #define B 2 #define C A + B #define PP_SLOT C #include "pp_slot.hpp" #undef A #undef B #define A 5 PP_HOLDER
これでPP_HOLDERは3に展開されます。なんと足し算とか普通に式で書いて計算できます。こいつなかなかやりますね。
ところでですね、pp_slot.hpp は一体何個#elifを並べるつもりなんですかねこれ。いっぱい並べるとか死にます。死んでしまってはいけないのでまぁがんばります。
#if !defined PP_SLOT_INCLUDED_ #define PP_SLOT_INCLUDED_ #define PP_SLOT_3 ((PP_SLOT) / 100 % 10) #define PP_SLOT_2 ((PP_SLOT) / 10 % 10) #define PP_SLOT_1 ((PP_SLOT) / 1 % 10) #define PP_DIGIT_CAT(a, b, c) PP_DIGIT_CAT_I(a, b, c) #define PP_DIGIT_CAT_I(a, b, c) a ## b ## c #define PP_HOLDER PP_DIGIT_CAT(PP_DIGIT_3, PP_DIGIT_2, PP_DIGIT_1) #endif #undef PP_DIGIT_1 #undef PP_DIGIT_2 #undef PP_DIGIT_3 #if PP_SLOT_3 == 1 #define PP_DIGIT_3 1 #elif PP_SLOT_3 == 2 #define PP_DIGIT_3 2 ... #elif PP_SLOT_3 == 9 #define PP_DIGIT_3 9 #endif #if defined PP_DIGIT_3 && PP_SLOT_2 == 0 #define PP_DIGIT_2 0 #elif PP_SLOT_2 == 1 #define PP_DIGIT_2 1 ... #elif PP_SLOT_2 == 9 #define PP_DIGIT_2 9 #endif #if PP_SLOT_1 == 0 #define PP_DIGIT_1 0 #elif PP_SLOT_1 == 1 #define PP_DIGIT_1 1 ... #elif PP_SLOT_1 == 9 #define PP_DIGIT_1 9 #endif #if !defined PP_DIGIT_3 #define PP_DIGIT_3 #endif #if !defined PP_DIGIT_2 #define PP_DIGIT_2 #endif #undef PP_SLOT
まぁ十分いっぱい並べてるわけですが、これで999まではうまく動きます。すばらしい。
一桁ずつ何の数字になるのか調べて、最後に連結しているわけですね。
ところでこれはまだ不完全です。#define PP_SLOT 100 / PP_HOLDER とかやるとどかーんってなります。PP_DIGIT_nは、各桁を調べる前にundefしています。じゃあundefしなければいいのかというと、そういうわけではありません。PP_HOLDERが3で、PP_SLOTが300 / PP_HOLDERだったとしましょう。まず百の位を調べて、PP_DIGIT_3を定義します。この時点でPP_DIGIT_3は1になるので、PP_SLOTを展開すると、300 / 13となりどかーん!なので、どのみち破綻します。
解決します。
#if !defined PP_SLOT_INCLUDED_ #define PP_SLOT_INCLUDED_ #define PP_SLOT_3 ((PP_SLOT) / 100 % 10) #define PP_SLOT_2 ((PP_SLOT) / 10 % 10) #define PP_SLOT_1 ((PP_SLOT) / 1 % 10) #define PP_DIGIT_CAT(a, b, c) PP_DIGIT_CAT_I(a, b, c) #define PP_DIGIT_CAT_I(a, b, c) a ## b ## c #define PP_HOLDER PP_DIGIT_CAT(PP_DIGIT_3, PP_DIGIT_2, PP_DIGIT_1) #endif #undef PP_DIGIT_TMP_1 #undef PP_DIGIT_TMP_2 #undef PP_DIGIT_TMP_3 #if PP_SLOT_3 == 1 #define PP_DIGIT_TMP_3 1 #elif PP_SLOT_3 == 2 #define PP_DIGIT_TMP_3 2 ... #elif PP_SLOT_3 == 9 #define PP_DIGIT_TMP_3 9 #endif #if defined PP_DIGIT_TMP_3 && PP_SLOT_2 == 0 #define PP_DIGIT_TMP_2 0 #elif PP_SLOT_2 == 1 #define PP_DIGIT_TMP_2 1 ... #elif PP_SLOT_2 == 9 #define PP_DIGIT_TMP_2 9 #endif #if PP_SLOT_1 == 0 #define PP_DIGIT_TMP_1 0 #elif PP_SLOT_1 == 1 #define PP_DIGIT_TMP_1 1 ... #elif PP_SLOT_1 == 9 #define PP_DIGIT_TMP_1 9 #endif #undef PP_DIGIT_1 #undef PP_DIGIT_2 #undef PP_DIGIT_3 #if !defined PP_DIGIT_TMP_3 #define PP_DIGIT_3 #elif PP_DIGIT_TMP_3 == 1 #define PP_DIGIT_3 1 #elif PP_DIGIT_TMP_3 == 2 #define PP_DIGIT_3 2 ... #elif PP_DIGIT_TMP_3 == 9 #define PP_DIGIT_3 9 #endif #if !defined PP_DIGIT_TMP_2 #define PP_DIGIT_2 #elif PP_DIGIT_TMP_2 == 0 #define PP_DIGIT_2 0 #elif PP_DIGIT_TMP_2 == 1 #define PP_DIGIT_2 1 ... #elif PP_DIGIT_TMP_2 == 9 #define PP_DIGIT_2 9 #endif #if PP_DIGIT_TMP_1 == 0 #define PP_DIGIT_1 0 #elif PP_DIGIT_TMP_1 == 1 #define PP_DIGIT_1 1 ... #elif PP_DIGIT_TMP_1 == 9 #define PP_DIGIT_1 9 #endif #undef PP_SLOT
PP_SLOTの各桁は一度PP_DIGIT_TMP_nに保存されるので、PP_DIGIT_nを破壊しても安心ですね。めでたしめでたし。
#define A 1 #define PP_SLOT A #include "slot_sample_3.hpp" #define PP_SLOT PP_HOLDER + 1 #include "slot_sample_3.hpp" #define PP_SLOT PP_HOLDER + 1 #include "slot_sample_3.hpp" #define PP_SLOT PP_HOLDER + 1 #include "slot_sample_3.hpp" #define PP_SLOT PP_HOLDER + 1 #include "slot_sample_3.hpp" #define PP_SLOT PP_HOLDER + 1 #include "slot_sample_3.hpp" #define PP_SLOT PP_HOLDER + 1 #include "slot_sample_3.hpp" #define PP_SLOT PP_HOLDER + 1 #include "slot_sample_3.hpp" #define PP_SLOT PP_HOLDER * 10 #include "slot_sample_3.hpp" #define PP_SLOT 720 / PP_HOLDER #include "slot_sample_3.hpp" PP_HOLDER
ちゃんと9になります。
おしまいです。今回はまぁ短いですね。ここまで書いてから、なぜこんなことを言いだしたのかという、いわゆるmotivationを思いついたので、いいじゃないですか、短くても。次回はそのへんを書こうと思いますが、めんどいので書かないかも知れません。それでは。
追記:
これも元ネタはBoost.PP.Slotで、誰も解説していなさそうなので書いてます。誰もそんなことしてほしくねーよボケが!