is式
is式は、 null値とis演算子の章で見たis演算子とは、構文的にも意味的にも関係がない。
is式は、コンパイル時に評価される。これは、括弧で指定された式に応じて、0または1のint値を生成する。この式が取る式は論理式ではないが、is式自体は、コンパイル時の論理式として使用される。これは、static if条件式やテンプレート制約で特に有用だ。
この式が取る条件は、常に型に関するもので、いくつかの構文のいずれかで記述する必要がある。
is (T)
Tが型として有効であるかどうかを判断する。
この時点では、この使用例を思いつくことは難しい。後の章で、テンプレートパラメータでこれを利用することにする。
intは有効な型である。
有効
別の例として、voidは連想配列のキー型としては有効ではないため、以下のelseブロックが有効になる。
出力:
無効
is (T Alias)
以前の構文と同じように動作する。さらに、AliasをTの別名として定義する:
このようなエイリアスは、以下で見るような、より複雑なis式で特に役立つ。
is (T : OtherT)
Tが自動的にOtherTに変換できるかどうかを決定する。
これは、型変換の章で見た自動型変換、および継承の章で見た"この型はあの型である"という関係などを検出するために使われる。
myFunction()テンプレートが、Clockのように使用できる型に対してインスタンス化されると、そのパラメータに対してtellTime()メンバー関数が呼び出される。それ以外の場合、else節がコンパイルされる。
これはClockである; 時刻を知ることができる ← AlarmClock用
10:00 ← AlarmClock用
これはClockではない ← int用
is (T Alias : OtherT)
以前の構文と同じように動作する。さらに、AliasをTの別名として定義する。
is (T == 指定子)
Tが 指定子と同じ型であるかどうか、またはTがその指定子と一致するかどうかを判断する。
同じ型かどうか
前の例を、:の代わりに==を使用するように変更すると、AlarmClockについては条件が満たされなくなる。
AlarmClockは Clockだが、Clockとまったく同じ型ではないからである。そのため、AlarmClockとintの両方で条件が満たされなくなった。
これはClockではない
これはClockではない
同じ指定子と一致するかどうか
指定子が次のキーワードのいずれかである場合、isのこの使用は、型がその指定子と一致するかどうかを判断する(これらのキーワードの一部は、後の章で説明する)。
関数テンプレートは、このような情報を利用して、テンプレートがインスタンス化される型に応じて異なる動作を行うことができる。次のコードは、上記のテンプレートの異なるブロックが、異なる型に対してどのようにコンパイルされるかを示している。
出力:
これはクラス型である
これは列挙型である
これは定数型である
これはその他の型である
is (T 識別子 == 指定子)
前の構文と同じように動作する。識別子は、型の別名、または指定子に応じてその他の情報になる。
指定子 | 識別子 |
|---|---|
struct | 条件を満たした型のエイリアス |
union | 条件を満たす型の別名 |
class | 条件を満たす型の別名 |
interface | 条件を満たした型の別名 |
super | 基底クラスとインターフェースからなるタプル |
enum | enumの実際の実装型 |
function | 関数パラメータで構成されるタプル |
delegate | delegateの型 |
return | 通常の関数、delegate、または関数ポインタの戻り値の型 |
__parameters | 通常の関数のパラメータ、delegate、または関数ポインタで構成されるタプル |
const | 条件を満たす型の別名 |
immutable | 条件を満たす型の別名 |
shared | 条件を満たす型の別名 |
この構文を試す前に、まずさまざまな型を定義しておこう。
次の関数テンプレートは、is式のこの構文で異なる指定子を使っている。
それでは、上で定義したさまざまな型で、この関数テンプレートを呼び出そう。
出力:
--- struct ---
コピーして新しいPointオブジェクトを構築する。
--- super ---
クラスAlarmClockには2つの基本型がある。
すべての基底型: (Object, Clock)
最上位の基底型: Object
--- enum ---
列挙型WeekDaysの実装型はint
--- return ---
これは、戻り値の型がcharの関数:
char function(double d, int i, Clock c)
これを呼び出すと... 結果は'a'になる
is (/* ... */ 指定子, テンプレートのパラメータリスト)
テンプレートパラメータリストを使用するis式には、4つの異なる構文がある。
is (T : 指定子, テンプレートのパラメータリスト)is (T == 指定子, テンプレートのパラメータリスト)is (T 識別子 : 指定子, テンプレートのパラメータリスト)is (T 識別子 == 指定子, テンプレートのパラメータリスト)
これらの構文により、より複雑なケースに対応できる。
識別子、指定子、:、および==は、上記で説明したのと同じ意味を持つ。
テンプレートのパラメータリストは、満たすべき条件の一部であると同時に、条件が実際に満たされた場合に追加のエイリアスを定義するための機能でもある。これは、テンプレート型の推論と同じように機能する。
簡単な例として、is式が、string型のキーを持つ連想配列と一致する必要があると仮定しよう。
この条件は3つの部分で説明でき、最後の2つはテンプレートのパラメータリストの一部である:
TがValue[Key]Valueが型の場合Keyがstringの場合(テンプレート特化構文を思い出して)
Value[Key]を指定子として使用するには、Tが連想配列である必要がある。Valueをそのままにしておくと、任意の型になる。さらに、連想配列のキーの型はstringでなければならない。その結果、前のis式は、"Tが、キーの型がstringである連想配列である場合"という意味になる。
次のプログラムは、4つの異なる型でis式をテストする。
条件は、キーの型がstringの場合にのみ満たされる。
--- intで呼び出された ---
いいえ、条件は満たされていない。
--- int[string]で呼び出された ---
はい、条件は満たされている。
値の型: int
キーの型 : string
--- double[string]で呼び出された ---
はい、条件は満たされている。
値の型: double
キーの型 : string
--- dchar[long]で呼び出された ---
いいえ、条件は満たされていない。