Standard
ECMA-372
C++/CLI 言語仕様書
西暦2005年12月 初版
ナビゲーション リンクのスキップ

13.変数

 この項は情報文です。

 標準C++ では、variable(変数)という用語は名前付きオブジェクト(標準 C++ §3/4 "基本コンセプト")を示すために使われます。
name(名前)とはエンティティやlabel(ラベル)(6.6.4, 6.1)を意味する識別子(2.10)の利用です。 variable(変数)はオブジェクトの宣言によって導入されます。変数の名前はオブジェクトを意味します。

 標準 C++ では、object(オブジェクト)という用語はデータ格納の領域を言及します。 (標準 C++ §1.8/1 "C++ オブジェクト・モデル")
C++ プログラム中の構成物は作られ、削除され、参照され、アクセスされ、そして、オブジェクトを操作します。 オブジェクトとは格納の領域です。 [注意:関数は、それがオブジェクトがするように何らかの方法でストレージを占めているといまいとに関わらず、オブジェクトではありません。]

 用語 CLI オブジェクトは CLI クラス型の任意のインスタンスを示します。用語 ネイティブ・オブジェクトはネイティブ・クラスのインスタンスを示します。

 情報文終わり。

13.1 gc-lvalue(GC左辺値)

 標準 C++ では、全ての式は lvalue(左辺値)ないし rvalue(右辺値)です。 C++/CLI では、式は gc-lvalue(GC左辺値)も取ることができます。それはガベージ・コレクタによる追跡をされるであろうオブジェクトを指します。 以下に記述された場合を除いて、標準 C++ を基盤とした lvalue(左辺値)と rvalue(右辺値)に期待されている振る舞いは変わりません。 C++/CLI では、全ての式は lvalue(左辺値)、gc-lvalue(GC 左辺値)、ないし、rvalue(右辺値)です。
 いくつかの作り付け演算子は gc-lvalue(GC 左辺値)を渡します。 [例:もし、E は"ハンドル型への"型の式であれば、 *E は gc-lvalue(GC左辺値)です。 関数 int% f(); は gc-lvalue(GC 左辺値)を渡すので、f() の呼び出しは gc-lvalue(GC 左辺値)です。]
 いくつかの演算子はオペランドが lvalue(左辺値)か gc-lvalue(GC 左辺値)かによって結果を生み出します。 [例:そのような演算子の一つに単項演算子 & があります。]
 追跡参照を返す関数呼び出しの結果は、追跡参照がネイティブ・クラスを示していない限り、 gc-lvalue(GC 左辺値)です。
 gc-lvalue(GC 左辺値)が期待されているコンテキストで lvalue(左辺値)が現れた場合はいつでも、lvalue(左辺値)は gc-lvalue(GC 左辺値)に変換されます。 同様に、rvalue(右辺値)が期待されるコンテキスト中に gc-lvalue(GC左辺値)が現れた時はいつでも、gc-lvalue(GC 左辺値)は rvalue(右辺値)に変換されます。
 参照初期化と一時オブジェクトは lvalue(左辺値)と rvalue(右辺値)同様に、gc-lvalue(GC 左辺値)を許せるようなセマンティクスを持っているべきです。
 lvalue(左辺値)のように、gc-lvalue(GC 左辺値)は任意の完全型、void 型、ないし、不完全型を持ち得ます。
 lvalue(左辺値)であるかのように、オブジェクトを編集するために、そのオブジェクトのための gc-lvalue(GC 左辺値)が使われるべきです。
 非修正可能 gc-lvalue(GC 左辺値)を通してオブジェクトを修正しようと試みるプログラムは不正です。
 標準 C++(§3.10/15)にある、lvalue(左辺値)を通してオブジェクトに蓄えられた値にアクセスするための制限のリストは、同様に gc-lvalue(GC 左辺値)にも適用されます。

13.1.1 標準変換

 標準 C++(§4.1)は以下のように追加されます。
任意の lvalue(左辺値)はgc-lvalue(GC左辺値)に変換されることができます。 gc-lvalue(GC左辺値)は lvalue(左辺値)から rvalue(右辺値)への変換が厳密に同じ場合、rvalue(右辺値)に変換されることができます。 そのほかの lvalue(左辺値)に gc-lvalue(GC左辺値)、gc-lvalue(GC左辺値)に rvalue(右辺値)変換を必要とするプログラムは不正です。

13.1.2 式

 標準 C++(§5/6)は以下のように追加されます。
もし、式が初期に" T への参照"型(8.3.2、8.5.3)を持っている場合、その式の型はどんなその先の解析にも優先して、その式が参照によって示されたオブジェクトや関数を指名した、"T"型に適合され、 式は lvalue(左辺値)となります。 もし、式が初期に" T への追跡参照"型を持っている場合、その式の型はどんなその先の解析にも優先して、その式が参照によって示されたオブジェクトや関数を指名した、 "T"型に適合され、式は gc-lvalue(GC左辺値)となります。
 一般的に、この章で示す任意のコンテキストにおいて、結果となるエンティティは関数、変数、または、データ・メンバであるか、もしエンティティがただ関数であれば それは lvalue(左辺値)であり、または、CLI ヒープ上でないデータ・メンバか変数であれば、式の結果は lvalue(左辺値)です。 もし、エンティティが変数、または、データ・メンバが CLI ヒープ上にある、ないし、なることができる場合には、結果は gc-lvalue(GC左辺値)です。 これは標準 C++ §5.1/4, §5.1/7, §5.1/8 で言及された状況に宛われます。式のエンティティは常にCLIヒープ上にある必要はありませんが、あるべきでしょう。 [例:その値クラスのデータメンバを参照する値クラスのメンバ関数はそのクラスがCLIヒープ上に領域確保されていると仮定しているため、gc-lvalue(GC左辺値)です。]
 標準 C++(§5.2.2/10)は以下のように変更されます。
関数呼び出しは、もし、そして、ただ、結果型がネイティブ参照である場合、lvalue(左辺値)です。 関数呼び出しは、もし、そして、ただ結果型が追跡参照である場合のみ、gc-lvalue(GC左辺値)です。
 標準 C++(§5.2.5/4)は以下のように変更されます。
――もし、E2 がメンバの列挙子で、E2 の型が T であれば、式 E1.E2 はlvalue(左辺値)ではありませんrvalue(右辺値)です。E1.E2 の型は T です。
 次のルールが標準 C++(§5.2.5/4)に追加されます。
――もし、E2 がref型か値クラスの静的データ・メンバで、E2 の型が T であれば、そのとき、E1.E2 はgc-lvalue(GC左辺値)です。 その式はクラスの名前付きメンバを指し示します。E1.E2 の型は T です。
――もし、E2 が非静的データ・メンバであれば、式は最初の式によって指し示されたオブジェクトの名前付きメンバを示します。
 標準 C++(§5.2.6/1)は以下のように変更されます。
...オペランドは修正可能な gc-lvalue になるべきです。...
 標準 C++(§5.3.1/1)は以下のように変更されます。
単項演算子 * は非直接的に実行します。:与えられた式はオブジェクト型のポインタ、もしくは、ハンドル、もしくは関数型へのポインタであるべきです 、そして、ポインタに非直接的に与えられているその式の結果は、その式が示している関数やオブジェクトを参照する lvalue(左辺値)です。 ハンドルに非直接的に適用した結果はオブジェクトを参照する gc-lvalue です。 もし、式の型が" T へのポインタ"であれば、その式の結果の型は" T "です。 もし、式の型が "T^" であれば、その結果は "T" です。 [注意:( cv void 以外の)不完全型へのポインタは参照を外すことができます。 lvalue(左辺値)は故にそこに含まれているものを限定された方法で使われることができます。 この lvalue(左辺値)はrvalue(右辺値)に変換することはできません。4.1 を見よ。]
 標準 C++(§5.3.1/2)は以下のように変更されます。
単項演算子 & の結果はそのオペランドへのポインタです。 そのオペランドは lvalue(左辺値)、gc-lvalue(GC左辺値)、ないし、qualified-id(修飾id)であるべきです。 もし、オペランドがlvalue(左辺値)であれば、与えられた式の型は"T"で、その結果は rvalue(右辺値)で、その型は"T へのポインタ"となります。 もし、オペランドが gc-lvalue(GC左辺値)であれば、与えられた式の型は"T"であり、その結果は rvalue(右辺値)で、その型は "T への interior_ptr" 型となります。 最初の場合、もし式の型が "T" ならば、その結果の型は"T へのポインタ"になります。 特に、"cv T" 型の型のオブジェクトのアドレスは同じ cv-qualifier を持った、"cv T へのポインタ"型です。 qualified-id(修飾id)のために、もし、メンバが "T" 型の静的メンバであれば、その結果の型は明白に"T へのポインタ"です。 もし、メンバがT型のクラスCの非静的メンバなら、結果の型は"T型のクラスCのメンバへのポインタ"です。
 標準 C++(§5.3.2/1)は以下のように変更されます。
...オペランドは修正可能な gc-lvalue であるべきです。...
 標準 C++(§5.16/3)の基本リストは以下のように拡大されます。
――もし、E2 が gc-lvalue であり、E1 は、もし、E1 が"T2 の追跡参照"型に暗黙のうちに変換されることができれば、 E2 にマッチするよう変換させることができるなら、変換時の拘束条件は参照を直接E1に結びつけるでしょう。
 標準 C++(§5.16/4)は以下のように拡大されます。
もし、二番目と三番目のオペランドが同じ型を持ち lvalue であれば、結果はその型であり、lvalue です。 もし、二番目と三番目のオペランドが同じ型を持ち gc-lvalue であれば、結果はその型であり、gc-lvalue です。
 標準 C++(§5.17/1)は以下のように変更されます。
いくつかの、そのグループの全ては右から左に代入する、代入演算子があります。 全てはその左辺のオペランドに修正可能な lvalue もしくは gc-lvalue を要請しており、そして、代入演算子の型はその左オペランドの型です。 代入演算子の結果は代入演算子が行われた後の左辺のオペランドに蓄えられた値です。 その結果はlvalueです。代入演算子の結果はもし左辺のオペランドが lvalue であれば lvalue です。 同様に代入演算子の結果は、もし、左辺のオペランドが gc-lvalue であれば、gc-lvalue です。
 標準 C++(§5.18/1)は以下のように拡大されます。
型と結果の値は右のオペランドの型と値です。もし、右辺のオペランドがそうであれば、その結果は lvalue です。 もし、右辺のオペランドが gc-lvalue であれば、その結果は gc-lvalue です。

13.1.3 参照初期化子

 標準 C++(§8.5.3)は以下のように追加されます。
ネイティブ参照は gc-lvalue(左辺値)に結びつけることはできません。もし、ネイティブ参照がrvalue(右辺値)に結びつけられたのであれば、 (標準 C++ §8.5.3/5 中に記述されているとおり)初期化式の一時オブジェクトが作成されるでしょう。 その一時オブジェクトは CLI ヒープの制御下にないメモリ上に領域確保されるべきです。

追跡参照は lvalue(左辺値)、ないし、gc-lvalue(左辺値)に結びつけることができます。
ネイティブ参照と異なり、追跡参照は rvalue に結びつくために const である必要はありません。
それは、int% r = 42; を正当な形式とします。追跡参照のバインディングは、それにもかかわらず、 ネイティブ参照と同じルールに従います。

ネイティブ参照式は常に lvalue(左辺値)であると見なします。追跡参照式は、追跡参照がネイティブ・クラスを参照する時を除いて、 常に gc-lvalue (左辺値)であると見なします。 追跡参照がネイティブ・クラスを参照するような場合には、lvalue(左辺値)です。


13.1.4 一時オブジェクト

 標準 C++(§12.2)は以下のように追加されます。
一時オブジェクトは右辺値であり、ネイティブ・ヒープ上に領域確保されるべきではありません。

13.2 ファイル・スコープ変数と名前空間スコープ変数

 メタデータの詳細は§34.3.1 を参照のこと。

13.3 直接的初期化

 標準 C++ における直接的初期化(§8.5 )は new 式、static_cast 式、関数表記の型変換、そして、基底とメンバの初期化中で発生します。 直接的初期化はコンストラクタとユーザー定義変換関数の双方であると見なします。 C++/CLI は CLI クラス型のための直接的初期化のこれら異なる形態の間で区別を行い、特定の場合においてコンストラクタと変換関数の使用を制限します。
  • もし、初期化中に new 式が場所を取っており、目的の型が CLI クラス型であった場合には、目的の型のコンストラクタであると見なします。 [注意:そのような new 式は文法の gcnew 形式のみを使っているでしょう。] 標準 C++(§8.5/14)は、この場合、変換関数へのどんな参照も取り除かれると拡張されます。
  • もし、初期化中に static_cast 式が場所を取っており、目的の型が CLI クラス型であった場合には、元となる型と目的の型との双方の変換関数であるとだけ見なします。 標準 C++(§8.5/14)はこの場合、コンストラクタへの任意の参照は削除するよう拡張されます。
  • もし、初期化中に関数表記の型変換が場所を取っており、目的の型が CLI クラス型であった場合には、目的の型のコンストラクタであるとだけ見なします。 標準 C++(§8.5/14)はこの場合、変換関数への任意の参照を削除するよう拡張されます。 §15.3.3 でさらに記述してあります。
  • もし、初期化中に基底とメンバの初期化が場所を取っており、目的の型が CLI クラス型であった場合には、目的の型のコンストラクタであるとだけ見なします。 標準 C++(§8.5/14)はこの場合、変換関数への任意の参照を削除するよう拡張されます。

文責:翻訳 => ヽ(゚∀。)ノうぇね