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]で呼び出された ---
いいえ、条件は満たされていない。