ゆとりーなの日記

日記的な事を書いて行くと思はれる

GNU擴張({})がやばい

普通複數のカウンタをインクリメントするfor文を書く場合、

for (i = j = 0; i < N; ++i, ++j) {
}

としますが、今日twitterにて

for (i = j = 0; i < N; ({++i; ++j;})) {
}

といつた回答を見かけたので、そんなん通る訣ないだらうと思つてコンパイルしてみたら通つてしまつて驚いたのです。
どうもこれはGNU擴張らしく(-pedanticを附けると"ISO C は式内を中括弧で括ることを禁止しています"といつた警告が出ます)、({})で式になるといふ素敵な擴張の樣です。詰りこれを使へばfor文の本體なんて要らんかつたんや!と云ふ事になります。

for (i = j = 0; i < N; ({printf("%d, %d\n", i, j); ++i; ++j;}));

これでカウンタを出力するfor文が書けてしまひます。驚きです。
で、どうやら{}の中の最後の式になる文を返す式になる樣なので、C++erなら一度はやりたいと思つたランキングに恐らく入つて來るであらう、

if (({const int c = getchar(); c == 'A';})) {
  puts("c is A");
}

かう云つたコードも實は書けた事になります。で、これを更に惡用すれば、

printf("%d\n", ({int i;
                if (({const int c = getchar(); c == 'A';})) {
                  i = 1;
                } else {
                  i = 0;
                }
                i;}));
}

といつた一見何かに使へさうなコードも書く事が出來ます。
正直これが便利なのは値を返すマクロとかになるんでせうか。例へばMIPSの制禦レジスタの値を讀むインラインアセンブリをマクロ化するとして、

const unsigned long reg = MFC0(0);

みたいに使はうと思つたら、

#define MFC0(n) ({unsigned long reg; __asm__ volatile ("mfc0 %0, $"#n"" : "=r"(reg) : ); reg;})

といつたマクロを用意すれば良ささうです(インライン函數で良くね?つてのは言はないお約束です!)。
で、更なる惡用として、匿名構造體みたいなのが作れないかと足掻いてみたのですが、

__typeof__(({struct {} s; s;})) hoge;

みたいなのがどうも通つて呉ないので無理さうです。structを({})の中で作るとどうも駄目みたいです(ifとかでは作れるんですけど__typeof__だと駄目)。
因みにラムダが有る今何に使ふんだと云ふ感はありますが、アルゴリズムに渡す匿名函數オブジェクトつぽいものがこれで作れてしまひます。

const std::vector<int> v = {0, 1, 2, 3};
std::cout << std::any_of(v.cbegin(), v.cend(), ({struct {bool operator ()(int x) const {return x == 0;}} s; s;})) << std::endl; 

本當誰徳です。__typeof__やdecltypeの中でstruct作れればunique_ptr等のカスタムデリータで匿名デリータが使へて或る意味夢が擴がつたんですけどね。殘念です。