2017年1月18日水曜日

c++で、scala風ifをやりたい

scalaをしばらくやっていると、c++を書いた時にifが値を返さないのでトサカにくることがある。

三項演算子とラムダ式を使えばもちろんできるんだけど、超絶汚くなる。けど、マクロにしたら案外すっきりしたので、記事アップ。
// scala風if
#define IF(COND) (COND)?[&](){
#define ELSE ;}():[&](){
#define ENDIF ;}()
#define IFRES return
こんな感じ。c++11以降ね。使うときは、
// scala風if sample1
    const int i = 5;
    const auto s = IF(i == 4) {
        cout << "case true" << endl;
        IFRES "if true!";
    } ELSE {
        cout << "case false" << endl;
        IFRES "if false!";
    } ENDIF;

    cout << s << endl;
そこそこ見やすい。ENDIFが必要なのは勘弁してね。
c++は、中括弧の最後の値が中括弧全体の値にならないので、IFの戻り値にしたい値にIFRESを付けてね。
IFRESは、ただのreturnなんだけど、直にreturnって書くと関数全体のreturnに見えてしまい、わけわからなくなるので、このキーワードを使います。
逆に言うと、IFやELSEの中から関数の外へ直接return出来ないので、あしからず。returnしたい人は、別にifの戻り値が欲しいわけじゃないので普通のifを使ってください。

あと、ENDIFマクロの最後にセミコロンをあえて含めずに、使うときにセミコロンをつけるようにしたのは、コンストラクタの初期化子でも使いやすくしたかったから。

IFとかELSEの後がブロックでなくてもOK。
// scala風if sample2
    const int i = 5;
    const auto s = IF(i == 4) IFRES "if true!"
                   ELSE IFRES "if false!"
                   ENDIF;
    cout << s << endl;