パスワードを忘れた? アカウント作成
1338391 journal
プログラミング

Yoh2の日記: [C/C++規格: 11] C11の新機能 その2 -- 型ジェネリック式

日記 by Yoh2

[2012-01-15 10:50変更: 疑似オーバーロードの話が大きくなりすぎたので独立したエントリーにしました。]

新機能一覧の概要はこちら→ [C/C++規格: 10] C11の新機能 その1 -- 新機能概要

スレッド周りと並び、一番興味を持ってたものなので最初に紹介。
# スレッド周りは重いから人に説明できるようになるまで苦労しそう。

■ 型ジェネリック式 (type-generic expression)
書式:

_Generic(制御式, 型名1: 式1, 型名2: 式2……)

※ 型名と式のペア (generic-association) は一組以上必要。
※ 型名は「default」(意味は後述)もあり。
※ 制御式、式nにコンマを含めた式を入れたい時は括弧で囲む。

意味:
直感的には型で分岐するswitch。
結果は制御式に適合する型を持つgeneric-associationの式の値になる。
defaultは他に適合する型がない時に選ばれる。
結果は左辺値やvoidや関数でもOK。つまりこんなこともできる。

int char_count, int_count, double_count, ocher_count;
...
// xの型に対応したカウンタ値をひとつ増やす。
_Generic(x, char: char_count, int: int_count, double: double_count, default: other_count)++;

また、制御式や選ばれなかったgeneric-associationの式は評価されない。

解説:
単体で使っても長々としてうれしくないが、マクロに使うと本領を発揮する。
例えば、C99でC++のオーバーロードのような動作を実現する<tgmath.h>のsinマクロは、C99の範囲だけでは処理系独自の実装を行わないと実現できなかったが、C11では似たようなマクロgeneric_sinを以下の様に定義できる。
(C11の<tgmath.h>のsinマクロの要件を完全に満たしているかどうかは未検証)

#define generic_sin(x) \
  (_Generic((x), \
    long double: sinl, \
    double: sin, \
    float: sinf, \
    long double _Complex: csinl, \
    double _Complex: csin, \
    float _Complex: csinf, \
    default: sin)(x))

雑感:
基本的な使われ方は解説で書いたような複数の関数の選択なんだろうけど (規格書に書かれている例も関数の選択だった)、他にも面白いことがいろいろとできそう。意味の所に書いた、型によるカウンタの選択とか。

あと、関数が選択できると言っても、これだけではC++のオーバーロードのように、引数の数が違うものまでは選択できない。でも可変長引数マクロと組み合わせればできるかな?えらく面倒になりそうだけど。
[2012-01-15 10:50変更: ここから]
……ということを考えてみたけど、今のところうまくいってない。0引数の場合をどうするかが問題に。
元々はこのエントリーに書いていたけど、大きくなったので引っ越しました。
C11で疑似関数オーバーロード (できてません)を参照。
[2012-01-15 10:50変更: ここまで]

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

開いた括弧は必ず閉じる -- あるプログラマー

読み込み中...