W.I.S. Laboratory
menu-bar

C++


C++のstd::stringでswitch~case~defaultをやってみる(その2)

C++のswitch文は整数型か列挙型でなければ使えない。(比較対象はCはリテラルかenumのみだが、C++はconst修飾していれば変数でも良い)
なのでfloatやdouble、std::stringなど、整数以外の型はまったく受け付けてくれず、こうした型はif~else ifを数珠つなぎにして書くほかないが、延々if~else ifを書くのはどうもキレイではない気がする。
特に文字列での処理振り分けは書く機会が増えてきているので、C++でもなんとか実現したい。
マクロを使ってもやってみたが、C++は絶えず進化しているので、その進化を使ったらなんとかならないものだろうか。

まずstd::mapを作り、キーをstd::string、値をstd::function<void(void)>にする。
case文で振り分けたい文字列をキーとし、それぞれの処理をラムダ式で書いてstd::mapに代入していく。
C++のラムダ式の正体は関数オブジェクトであり、複数のラムダ式はすべて型が異なるためそのままではstd::mapの値としては格納できないのたが、std::functionでラップするとシグネチャが同じものに限っては同型扱いしてくれるので、引数・戻り値共にvoidでありさえすれば複数のラムダ式をstd::mapに格納できるようになる。
こうして作成したstd::map型変数に対してstd::string型の変数をキーとして与え、関数として呼び出すと、switch~caseに似た処理の振り分け動作になる。

ただ、この方法だとdefault処理が難しい。
キーが存在しないと実行時エラーになってしまうからだ。
仕方ないのでキーの存在を調べて、キーが無いときはそれ専用のラムダ式を呼び出すことにした。
今回は "_" をキーとして、そこにdefault処理を書いたラムダ式を代入してみたが、何もstd::mapに格納する必要はないので適当な変数に入れておいてもいいと思う。
あとはstd::mapのcontains関数(C++20以降で使用可能)でキーの存在を調べ、キーがあればそのキーに格納されたラムダ式を呼び、無ければdefault処理を書いたラムダ式を呼べば、switch~case~defaultと同等になる。

性格的に三項演算子内に処理は書きたくないのだが、ここでif文を使うのもなんか悔しい。
すぐに実行せず、一度変数に格納してから呼び出したほうがキレイかもしれない。

もちろん、ifを使っても何も悪くない。

こんな感じになったが、正直読みやすいとは言えない気がする。
分岐がものすごい数になってくると&各処理の行数が増えてくると、延々if~else ifを繋げたコードよりはいくらかマシだろうか・・。


[ 戻る ]
saluteweb