こんにちは、高木です。
長い間、PHPでC言語の前処理を行う話題が続いてきました。このあたりでちょっと違う話題に移りたいと思います。といっても、PHPでC++の前処理を行う話題なので、C言語前処理の流れをそのまま引き継ぐことになります。
対象がC++になってもC言語のときと基本は変わりません。しかし、C++の方がC言語よりPHPが威力を発揮することは多いと思います。C++ではテンプレートやマクロを駆使して高度なメタプログラミングが可能になりますが、PHPを使った方が明らかに楽なケースは多いのです。今回は一例として演算子の多重定義を取り上げてみたいと思います。まずは、以下のようなC++のクラスを考えてみることにしましょう。
0 1 2 3 4 5 6 7 8 9 |
class my_int { public: my_int(int value = 0) : value_(value) {} int get() const { return this->value_; } private: int value_; }; |
話を簡単にするために最小限のメンバーしか記述していませんが、int型の値のラッパークラスです。このクラスのために等価演算子と関係演算子を多重定義してみましょう。
0 1 2 3 4 5 6 7 8 9 10 |
bool operator==(const my_int& lhs, const my_int& rhs) { return lhs.get() == rhs.get(); } bool operator<(const my_int& lhs, const my_int& rhs) { return lhs.get() < rhs.get(); } |
ここでは==演算子と<演算子だけを多重定義しました。残りの等価演算子と関係演算子は、これら2つの演算子を使って定義することができますが、非常に退屈な単純作業が待っています。こういうのはぜひ自動化したいものですが、演算子をテンプレート引数にすることはできません。std::rel_opsを使ってくださいというのも不親切ですし、三方比較演算子(宇宙船演算子と読んだ方が分かりやすいかもしれませんね)はC++20からでないと使えません。こんなときこそPHPの出番です。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php foreach ([ '==', '!=', '<', '>', '<=', '>=' ] as $op) { echo <<< EOT bool operator{$op}(const my_int& lhs, const my_int& rhs) { return lhs.get() {$op} rhs.get(); } EOT; } ?> |
これだけ書いてあげれば、6種類の演算子があっという間に定義できてしまいます。あとからinlineを付けたいとかconstexprを付けたいとかの要望が出ても簡単に修正することができます。
同じようにすれば、算術演算子やビット単位の演算子も簡単に実装できます。シフト演算子はちょっと事情が違うかもしれませんが、仕様次第では同じように実装してもいいでしょう。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php foreach ([ '+', '-', '*', '/', '%', '&', '|', '^' ] as $op) { echo <<< EOT my_int operator{$op}(const my_int& lhs, const my_int& rhs) { return lhs.get() {$op} rhs.get(); } EOT; } ?> |
こんな感じで、C++こそPHPで前処理する価値があります。