プリプロセッサで代入しましょう!

さて今回は代入です。とはいっても関数マクロを展開中に代入とかは無理です。なので、#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で、誰も解説していなさそうなので書いてます。誰もそんなことしてほしくねーよボケが!