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

33.CLI ライブラリ


33.1 独自修飾子

 標準 C++ の実装は名前マングリングによって異なるシグネイチャ間を区別します。 しかしながら、これは言語固有の解決方法であるばかりでなく、使われるマングリング・スキームはある実装ある実装ごとに変わっています。 そのため、このアプローチは、異なる C++ 実装間での相互互換性が要請され、異なった言語間での相互互換性を期待される C++/CLI には適していません。独自修飾子はこの問題に取り組みます。
 modreq("required modifier 必須修飾子") と modopt("optional modifier 随意修飾子") を使って ILAsm において定義されている custom modifier(独自修飾子)(CLI標準、パーティションII、"型とシグネイチャ")は、カスタム修飾子が宣言シグネイチャの一部であることから、カスタム属性が宣言にアタッチされるという点を除いてカスタム属性と同等です。各々の独自修飾子はシグネイチャ中のアイテムの型参照に結びついています。 独自修飾子の( required ないし optional の)追加のみが異なる二つのシグネイチャは同一であるとは見なしません。シグネイチャの一致性は§33.1.1 においてさらに議論します。独自修飾子は VES の操作には他に何の効果も持ちません。

33.1.1 シグネイチャ・マッチング

 以下のようなクラス定義について考えます。
public ref class X {
public:
    static void F(int* p1) { ... }
    static void F(const int* p1) { ... }
private:
    static int* p3;
    static const int* p4;
};
 これら4つのメンバのシグネイチャはメタデータ中に以下のように保存されます。
.method public static void F(int32* p1) ... { ... }
.method public static void F(int32
  modopt([mscorlib]System.Runtime.CompilerServicesn.IsConst)* p2) ... { ... }
.field private static int32* p3
.field private static int32
  modopt([mscorlib]System.Runtime.CompilerServicesn.IsConst)* p4
[注意:CLI コンテキスト中では、型の完全修飾名はドット(.)分割子で、C++ コンテキスト中ではその代わりに二つのコロン(::)が使われます。]
 明らかに F の二つのシグネイチャは異なり、これらの宣言は多重定義として許されています。
 これらの関数呼び出しとそれらが生み出す対応したコードは次の通りです。
int* q1 = 0;
X::F(q1);
call void X::F(int32*)
const int* q2=0;
X::F(q2);
call void X::F(int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst)*)
 call 命令の厳密なシグネイチャ一致を使って正確な関数が呼び出されます。(もし、実行時に一致するシグネイチャが一つも存在しなければ、System::MissingMethodException 型の例外が投げられます。)
 データ・メンバへのアクセスは同様の装いをもってマッチされます。
static void F(int* p) {
    p3 = p1;
    p4 = p1;
}
.method public static void F(int32* p1) ... {
  ...
  ldarg.0
  stsfld int32* X::p3
  ldarg.0
  stsfld int32
    modopt([mscorlib]System.Runtime.CompilerServices.isConst)* X::p4
  ...
}
static void F(const int* p2) {
    p4 = p2;
}
.method public static void F(int32 modopt([a]n.IsConst)* p2) ... {
  ...
  ldarg.0
  stsfld int32 modopt([mscorlib]System.Runtime.CompilerServices.isConst)*
    X::p4
  ...
}
 フィールドは stsfld 命令中の厳密なシグネイチャ一致を使ってアクセスされます。(もし、実行時に一致するシグネイチャが見つからなければ、System::MissingFieldException 型の例外が投げられます。)

33.1.2 modreq vs. modopt

 必須(required)と随意(optional)の修飾子間の差違は(コンパイラのような)メタデータを扱うツールには重要です。必須修飾子は修正されたアイテムに特別な意味論があることを示しており、それは無視することはできないが、随意修飾子は単純に無視されるかもしれません。例えば、volatile 修飾されたデータ・メンバは IsVolatile modreq でマークされるべきです。この修飾子の存在は、そのようなメンバの全てのアクセスは volatile. 前置命令(例えば、§33.1.5.9 )の使用を含んでいるため、無視することはできません。他方、const 修飾子は、const 修飾されたデータ・メンバやパラメータは const 修飾されたオブジェクトへのポインタであるので、modopt でモデルすることができるため、特別な扱いを必要としません。
 CLI はそれ自身、必須と随意の修飾子を同じ振る舞いで扱います。

33.1.3 修飾子文法

 以下の文法はフィールドとメソッドについて CLI 標準で定義されたもののサブセットです。解説のために、抜粋はかなり単純化してあります。(完全で、単純化されていないバージョンは、CLI 標準のパーティションIIを参照のこと)
Field:
.field Type Id
Method:
.method Type MethodName ( Parameters ) { MethodBody }
Parameters:
[ Param [ , Param ]* ]
Param:
Type [ Id ]
Type:
...
int32
Type *
Type [ ]
Type modreq ( [ AssemblyName ] NamespaceName . Id )
Type modopt ( [ AssemblyName ] NamespaceName . Id )
 Field 中の Id はデータ・メンバの名前を指します。Param 中の Id はオプション関数パラメータの名前を示します。 この名前は関数のシグネイチャの一部ではありません。modopt と modreq の Type 中の Id は独自修飾子型の名前です。 この型は public 可視性を持つ非ネスト型 ref クラスであるべきです。[注意:概して、修飾子クラスは sealed であり、public メンバを持ちません。]
[例:ここにいくつかのデータと関数メンバの定義と、それらのそれぞれの宣言によって生成されるメタデータを置きます。
public ref class X {
    int f1;
    const int f2;
    const int* f3;
    const int** f4;
    const int* const* f5;

    array<int>^ f6;
    array<int*>^ f7;
    const array<int>^ f8;
    array<const int>^ f9;
    const int* F() { ... }
    void F(int x, const int* y, array<int>^z) { ... }
};
.field private int32 f1
.field private int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst) f2
.field private int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst)* f3
.field private int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst)** f4
.field private int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst)*
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst)* f5
.field private int32[] f6
.field private int32*[] f7
.field private int32[]
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst) f8
.field private int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[] f9

.method private instance int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst)*
  F() ... { ... }
.method private instance void F(int32 x,
  int32 modopt([mscorlib]System.Runtime.CompilerServices.IsConst)*
  y, int32[] z) ... { ... }


33.1.4 複数の独自修飾子を持つ型

 Type は複数の modreq と/または、modopt を含むことができます。[例:
public ref class X {
    const volatile int m;
};
.field private int32
  modreq([mscorlib]System.RuntimeCompilerServices.IsVolatile)
  modopt([mscorlib]System.RuntimeCompilerServices.IsConst) m


33.1.5 標準カスタム修飾子

 (CLI標準で定義されている)IsVolatile を例外として、この節で文書化されている全ての修飾子は C++/CLI 特殊です。
 これらの修飾子型は sealed で、System::Object から派生しており、その public キーは [00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00] であり、それらは CLSCompliantAttribute(true) 属性を持ち、ライブラリ RuntimeInfrastructure に属し、名前空間 System::Runtime::CompilerServices 中に位置し、アセンブリ mscorlib の一部です。

33.1.5.1 IsBoxed
[注記:この modreq 型はこの標準において必須とされておりません。しかしながら、少なくとも、ある実装において値型にハンドル型強調子 ^ が使われる時をサポートするため規定します。
詳細:
 この型はそのメンバが値型へのハンドルを示す任意のデータ・メンバのシグネイチャ中で使われます。 それはまた、値型へのハンドルである返値型とパラメータを指し示す関数シグネイチャにも使われます。 発行されるときには、この型は直ちに class [mscorlib]System.ValueType と modopt(v) 、v は値型の名前です、によって、その順に先行されるべきでしょう。[例:
public value class V {};
public ref class C {};

public ref class X { 
    int* m1;
    int^ m2;
    V^ m3;
    C^ m4;

public:
    void F(int* x) { … }
    void F(int^ x) { … }
    const signed char^ F(V^ v, C^ c) { … }
};
.field private int32* m1
.field private class [mscorlib]System.ValueType
  modopt([mscorlib]System.Int32) 
  modreq([mscorlib]System.Runtime.CompilerServices.IsBoxed) m2

.field private class [mscorlib]System.ValueType modopt(V)
  modreq([mscorlib]System.Runtime.CompilerServices.IsBoxed) m3

.field private class C m4

.method public instance void F(int32* x) … { … }

.method public instance void F(class [mscorlib]System.ValueType
  modopt([mscorlib]System.Int32)
  modreq([mscorlib]System.Runtime.CompilerServices.IsBoxed) x) … { … }

.method public instance class [mscorlib]System.ValueType
  modopt([mscorlib]System.Runtime.CompilerServices.IsConst)
  modopt([mscorlib]System.SByte)
  modreq([mscorlib]System.Runtime.CompilerServices.IsBoxed)
  F(class [mscorlib]System.ValueType modopt(V)
  modreq([mscorlib]System.Runtime.CompilerServices.IsBoxed) v,
  class C c) … { … }
 m2 の場合には、そのシグネイチャはそのフィールドが System::ValueType 型へのハンドルであることを指し示します。 値型の特定の種類は、その時、int 型である [mscorlib]System.Int32 型に続いて値型の特殊な modopt で指し示されます。 同様に、m3 の場合には、この値型の特殊な modopt はユーザー定義型 V です。 F の二番目と三番目の多重定義はまた、期待されているとおり、int と unsigned char を示す、[mscorlib]System.Int32 と [mscorlib]System.SByte と言う名の値型の特殊な modopt を使います。この例で示されているように、値型の特殊な modopt は任意の値型であり得ます。型が値型でなく ref 型であるような C は modopt 生成の結果となりません。]

33.1.5.2 IsByValue
 この modreq 型は値としてで ref クラス型のオブジェクトが渡されることをサポートします。
詳細:
 この型は関数のシグネイチャ中で利用されます。しかしながら、関数によって返される ref クラス値を指し示すのには使われません。 それには、IsUdtReturn(§33.1.5.8 )を参照のこと。[例:
public ref struct R {
    static void F(R r) { ... }
};
.class public ... R ... {
  .method public static void F(class R modopt(
    [mscorlib]System.Runtime.CompilerServices.IsByValue) r) ... { ... }


33.1.5.3 IsConst
 この modopt 型は const 修飾子をサポートします。
詳細:
 この型は任意のデータ・メンバ、ないし、関数のシグネイチャに使うことができます。
 この修飾子の数多くの例が§33.1.1 §33.1.3 、そして、§33.1.4 で見ることができます。

33.1.5.4 IsExplicitlyDereferenced
 この modopt 型は interior ポインタとピンニング・ポインタの使用をサポートします。
詳細:
 この型は任意の関数やローカル変数のシグネイチャとして使うことができます。[例:
public ref struct X {
    void F(interior_ptr<int> x) { … }
    void F(interior_ptr<unsigned char> x) { … }
};
.method … void F(int32& modopt(
  [mscorlib]System.Runtime.CompilerServices.IsExplicitlyDereferenced) x)
  … { … }
.method … F(unsigned int8& modopt(
  [mscorlib]System.Runtime.CompilerServices.IsExplicitlyDereferenced) x)
  … { … }


33.1.5.5 IsImplicitlyDereferenced
 この modopt 型は参照型前置詞 & と % をサポートします。
詳細:
 この型はメンバが参照であるものを指し示す任意のデータ・メンバのシグネイチャ中で使用されます。 その型は、また、パラメータとして参照を渡したり、参照で値を返す関数を指し示す関数シグネイチャ中でも使用されます。[例:
ref class X {
    int* m1;
    int& m2;
public:
    void F(int* x) { … }
    void F(int& x) { … }
    void F(X%x) { …}
    int& G() { … }
};
.field private int32* m1
.field private int32* modopt(
  [mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) m2
.method … void F(int32* x) … { … }
.method … void F(int32* modopt( 
  [mscorlib]System.Runtime.CompilerServices.IsImplicitlyDereferenced) x)
  … { …}
.method … void F(class X modreq([mscorlib]
  System.Runtime.CompilerServices.IsImplicitlyDereferenced) x) … { … }
.method … int32* modopt([mscorlib] 
  System.Runtime.CompilerServices.IsImplicitlyDereferenced) G() … { … }


33.1.5.6 IsLong
[注記:この modopt 型はこの標準の部分ではありません。しかしながら、それは二つの関連性のない目的のために少なくとも一つの実装によって使用されています。:型 long int と unsigned long int を int と unsigned int と同様に扱い、そして、型 long double を double と同様に扱うため。
詳細:
 IsLong は任意のデータ・メンバや関数のシグネイチャ中で使うことができます。[例:
public ref class X {
    int i;
    long int li;
    double d;
    long double ld;
public:
    unsigned int F(unsigned int* pu) { … }
    unsigned long int F(unsigned long int* pul) { … }

    double F(double* pd) { … }
    long double F(long double* pld) { … }
};
.field private int32 i
.field private int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsLong) li

.field private float64 d
.field private float64
  modopt([mscorlib]System.Runtime.CompilerServices.IsLong) ld
.method … unsigned int32 F(unsigned int32* pu) … { … }
.method … unsigned int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsLong)
  F(unsigned int32
  modopt([mscorlib]System.Runtime.CompilerServices.IsLong)* pul)
  … { … }
.method … float64 F(float64* pd) … { … }
.method … float64
  modopt([mscorlib]System.Runtime.CompilerServices.IsLong)
  F(float64 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)*
  pld) … { … }


33.1.5.7 IsSignUnspecifiedByte
 この modopt 型は素の char を signed char と unsigned char と分離した型としてサポートします。
詳細:
 この型は任意のデータ・メンバや関数のシグネイチャ中で使うことができます。[例:
public ref class x {
    char c;
    signed char sc;
    unsigned char uc;
public: 
    char* F(char* p1) { … }
    char* F(signed char* p2) { … }
    char* F(unsigned char* p2) { … }
}; 
 コードは素の char が符号付きであるという実装では次のように生成されます。
.field private int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte) c
.field private int8 sc
.field private unsigned int8 uc
.method … int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte)*
  F(int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte)* p1)
  … { …}
.method … int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte)*
  F(int8* p2) … { … }
.method … int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte)*
  F(unsigned int8* p2) … { … }
 素の char が符号無しである実装系では以下に示すように生成されています。
.field private unsigned int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte) c
.field private int8 sc
.field private unsigned int8 uc
.method … unsigned int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte)*
  F(unsigned int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte)* p1)
  … { …}
.method … unsigned int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte)*
  F(unsigned int8* p2) … { … }
.method … unsigned int8 modopt(
  [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte)*
  F(unsigned int8* p2) … { … }


33.1.5.8 IsUdtReturn
 この modopt 型は ref クラス型を値としてオブジェクトを返すことをサポートします。
詳細:
 この型は関数のシグネイチャ中に使用されます。しかしながら、関数に渡す ref クラス値を示すためには使われません。 そのためには、IsByValue(§33.1.5.2 )を参照のこと。[例:
public ref struct R {
    R() { … }
    R(R% r) {… }
    R F() { … }
};
.method … void modreq([mscorlib]
  System.Runtime.CompilerServices.IsUdtReturn) F(class R& A_1) … { … }
]

33.1.5.9 IsVolatile
 この modreq 型は volatile 修飾子をサポートします。( IsVolatile は CLI 標準の一部ではあるのですが、簡便のために、ここに同様に文書化します。)
詳細:
 この型は任意のデータ・メンバや関数のシグネイチャ中で使うことができます。
 volatile 修飾をされたデータ・メンバ、ローカル変数、そして、パラメータ宣言はこの modreq によってマークされるべきです。 さらに加えて、それらのようなメンバ、変数やパラメータへのアクセスごとに、この modreq でマークされるべきです。
 vlotatile modreqを含むシグネイチャ・アイテムを持っているメタデータを取り込む任意のコンパイラは volatile. 前置命令を、volatile修飾されているメモリ領域にアクセスする時に、使うことを要請されます。
[例:
public ref class x {
    volatile int* p1;
public:
    void F(volatile int* p2, int* p3)
    {
        *p1 = 1;
        *p2 = 2;
        *p3 = 3;
        p1 = 0;
    }
};
.field private int32
  modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile)* p1

.method … void F(int32
  modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile)* p2,
  int32* p3) … {
  …
  ldarg.0
  ldfld int32 modreq([mscorlib]
     System.Runtime.CompilerServices.IsVolatile)* x::p1
  ldc.i4.1
  volatile. // p1 の参照外しをする時、前値命令が必要とされる
  stind.i4

  ldarg.1 
  ldc.i4.2 
  volatile. // p2 の参照外しをする時、前値命令が必要とされる
  stind.i4 

  ldarg.2 
  ldc.i4.3 
  stind.i4 // p3 の参照外しには、前値命令は不要

  ldarg.0 
  ldc.i4.0 
  stfld int32 modreq([mscorlib] 
      System.Runtime.CompilerServices.IsVolatile)* x::p1
          // p1 の参照外しではないので、前値命令は不要
  ret
}
 与えられた宣言 volatile int* p1 について、p1 はそれ自身は volatile修飾されておらず、*p1 が修飾されていると言うことに注意してください。


33.2 標準属性

 C++/CLI 実装に準拠するには以下に記述する属性型を提供するべきでしょう。

33.2.1 NativeCppClass

 各々のネイティブ・クラスはメタデータ中に属性 NativeCppClass のマークを付けた値クラスとしてエンコードされています。それは以下のように定義されます。
 [System::AttributeUsage(System::AttributeTargets::Struct,Inherited=true)]
 public ref class NativeCppClassAttribute sealed : System::Attribute {
 public:
     NativeCppClassAttribute() { /* ... */ }
 };
 この型は次のような記述を持っています:public key [00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00] であり、属性 CLSCompliantAttribute(true) を持ち、ライブラリ RuntimeInfrastructure に属し、名前空間 System::Runtime::CompilerServices にあり、そして、アセンブリ mscorlib の一部です。

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