追記 F. 将来の方向性
この追記は説明文です。
この追記はこの標準が将来、改訂されるだろう項目についての情報を含めています。
F.1 演算
F.1.1 クラス・メンバ・アクセス
名前付きインデックス・プロパティがクラスの他の任意のメンバのようにアクセスできます。
[注記:期待されているのは、p->NamedIndexer[index] 形式の表記が (*p).NamedIndexer[index] と等価となること。]
F.1.2 型識別
CLI クラス型の typeid の方法を以て、std::type_info を生成するよう検討します。
F.1.3 ポインタ型可搬性
プログラムを実行するハードウェアの設計によってポインタ型のサイズが決まります。
CLI ではポインタ型のサイズが違う複数のハードウェア設計上で実行できるできるプログラム中でポインタ型を使うことができます。
そのようなプログラムをサポートするためには、ポインタ型の sizeof 演算はコンパイル時定数ではなく実行時演算に移し変わるべきでしょう。
F.2 構文
F.2.1 checked と unchecked 命令文
checked { ... } と unchecked { ... } 形式の命令文が整数型演算の計算と変換のオーバーフローチェックを制御するコンテキストとして使えるようにします。
F.3 クラス
F.3.1 デリゲート化コンストラクタ
チュートリアル:クラスを実装するとき、いくつかの共通コードを多くのコンストラクタで持っていることは普通ではありません。
例えば、以下のポイントクラスについて考えてみます。
class point {
int x_;
int y_;
void commonCode();
public:
point();
point(int x, int y);
point(const point& p);
...
};
三つのコンストラクタすべてが、二つのプライベート・メンバ、x_ と y_ を初期化する必要があります。
それらは他の、あるものは共通な、そして、またあるものは特別なアクションも実行するかもしれません。
一つのアプローチとしては次のように、
point::point() : x_(0), y_(0) {
commonCode();
// 特定コードをここに記述
}
point::point(int x, int y) : x_(x), y_(y) {
commonCode();
}
point::point(const point& p) : x_(p.x_), y_(p.y_) {
commonCode();
// 特定コードをここに記述
}
確かに、パラメータを持たないコンストラクタは二つの引数をデフォルトに与えることで除去することができます。
しかし、それではすべてのクラスについて満足することができるアプローチと言えません。
特別に、一つの引数のみで二番目のみではなく、呼び出される二つの引数を持つコンストラクタを許しており、それは哲学的に非対称的となります。
上に示したように、そのようなコンストラクタの一族を実装するような共通のアプローチは、その共通コードを commonCode といった、プライベート・メンバ関数として、配置し、それぞれがその関数を呼び出すことになります。
C++/CLI はこの問題を解決するために、
デリゲーティング・コンストラクタ(delegating consutuctor)を提供したいです。
単純に配置され本文に先んじて実行されるデリゲーティング・コンストラクタは、その親族のコンストラクタのひとつを基底コンストラクタであるかのように呼び出すことができます。
それは、他のコンストラクタのオブジェクト初期化の一部をデリゲートとして、コントロールを取り戻します。そして、同様にオプションとしてその他のアクションを実行します。
このアプローチを取ることで、先に示したようなコンストラクタは以下のように再実装することができます。
point::point() : point(0, 0) {
// 特定コードをここに記述
}
point::point(int x, int y) : x_(x), y_(y) {
// 共通コードをここに記述
}
point::point(const point& p) : point(p.x_, p.y_) {
// 特定コードをここに記述
}
どうやって、基底クラス・コンストラクタ呼び出しとまったく同じアプローチを使って、並ぶコンストラクタの呼び出しを順応させて
ctor-initializer 生成が拡張されているかに注意してください。
共通コード命令文はいまや2番目のコンストラクタの本体の部分となり、三つのコンストラクタすべてから呼び出され実行されることとなります。
最初と3番目のコンストラクタが呼ばれると、それらは2番目のコンストラクタに制御を移します。
その制御が呼び出し側に帰ってくると、呼び出し側は自身の本分を実行します。
任意のコンストラクタはその同胞を任意に委譲することができます。
しかし、クラスは少なくともひとつの非デリゲート・コンストラクタ(検証が必要としない)を持っているべきであり、そのコンストラクタはひとつ以上の基底クラスのコンストラクタを呼ぶ
ctor-initializer を持つことができます。
また、デリゲート・コンストラクタはコンマ区切りにされたメンバの初期化を含む
ctor-initializer を持つことはできません。
仕様:
ctor-initializer の定義は C++/CLI によるデリゲート化コンストラクタの追加を協調するよう拡張されます。
しかしながら、標準C++ (§8.4)の文法には何の変更も必要ありません。
その本文を実行するより前に、コンストラクタはメンバを初期化するためにその同胞たるコンストラクタのひとつを呼ぶことができます。
それは、そのオブジェクトの初期化を他のコンストラクタに移譲することで、制御を取り戻します。
そして、その時、同様にその他のアクションを実行することをオプションとします。
この振る舞いで移譲を行うコンストラクタをデリゲート化コンストラクタと呼び、それが移譲するコンストラクタのことをターゲット・コンストラクタと呼びます。
デリゲート化コンストラクタは、また、いくつかの他のデリゲート化コンストラクタをターゲット・コンストラクタとすることもできます。[例:
class FullName {
string firstName_;
string middleName_;
string lastName_;
public:
FullName(string firstName, string middleName, string lastName);
FullName(string firstName, string lastName);
FullName(const FullName& name);
};
FullName::FullName(string firstName, string middleName, string lastName)
: firstName_(firstName), middleName_(middleName), lastName_(lastName)
{
...
}
// デリゲート・コピー・コンストラクタ
FullName::FullName(const FullName& name)
: FullName(name.firstName_, name.middleName_, name.lastName_)
{
...
}
// デリゲート・コンストラクタ
FullName::FullName(string firstName, string lastName)
: FullName(firstName, "", lastName)
{
...
}
]
もし、
mem-initializer-id が定義されたクラスを指し示すなら、それはただ
mem-initializer であるべきでしょう。
結果としての
ctor-initializer はその定義されたコンストラクタをデリゲート化コンストラクタであると意味します。
デリゲート化コンストラクタはそれ自身のクラスからコンストラクタが呼び出されることを引き起こします。
ターゲット・コンストラクタは通常、多重定義解決とテンプレート型推論によって選択されます。
もし、デリゲート化コンストラクタの定義が直接的、非直接的にそのコンストラクタ自身を呼び出す
ctor-initializer を含んでいる場合には、そのプログラムは不正となります。
しかしながら、検証は必要としません。
[例:テンプレートであるコンストラクタを使うとき、型推論は通常通り機能します。
class X {
template<class T> X(T, T) : l_(first, last) { /* 共通初期化 */ }
list<int> l_;
public:
X(vector<short>&);
};
X::X(vector<short>& v) : x(v.begin(), v.end()) { }
// T は vector<short>::iterator と型推論される
]
オブジェクトの生存時間はすべてのコンストラクタが成功のうちに完了したときから始まります。
標準C++(§3.8)の目的では"コンストラクタ呼び出しが完了する"とは元々のコンストラクタ呼び出しを意味しています。
[解釈:ターゲットのコンストラクタが完了したとしても、外部デリゲート化コンストラクタは未だに例外を投げることが可能であり、そして、それ故に、呼び出し側は要請されたオブジェクトを得ない場合があり得ます。
前述の決定はまた標準C++のルール、例外をコンストラクタから投げられることはオブジェクトの生存時間が始まっていないことを意味しています、を維持しています。]
F.3.2 プロパティ
ネイティブ・クラスにプロパティを許します。
プロパティにそのアクセサと同じように、または、その代わりとして、一つ以上の abstract, new, override, そして、sealed を修飾子として直接与えることができるようにします。
F.3.3 イベント
イベントにそのアクセサと同じように、または、その代わりとして一つ以上の abstract, new, override, そして、sealed を修飾子として直接与えることができるようにします。
F.3.4 未サポートのCLS-勧告演算子
| アセンブリ中の関数名 | C++ 演算子関数名 |
| op_SignedRightShift | 未定義 |
| op_UnsignedRightShift | 未定義 |
| op_MemberSelection | 未定義 |
| op_PointertoMemberSelection | 未定義 |
| |
op_MemberSelection と op_PointerToMemberSelection に関して、標準 C++ はこれらの演算の宣言を非静的メンバにのみ許しています。
F.3.5 演算子の true と false
true 演算子、false 演算子を定義する能力を追加します。
F.4 ジェネリック型
CLI は開いた生成ジェネリック型(
§31.2.1 )に関連する System::Type オブジェクトの取得を許していますが、C++/CLI ではこれを行うための構文を提供していません。
しかしながら、その構文は将来考案されるでしょう。
F.5 独自修飾子
F.5.1 IsPinned
この modopt 型はパラメータとして pin_ptr 型の使用をサポートします。
- 記述:
-
この型は任意の関数のシグネイチャとして使われます。
[例:
public ref class X {
public:
void F(pin_ptr<int> x) { ... }
};
]
F.6 属性
X と XAttribute と呼ばれる二つの属性の間を曖昧なく選択できる能力を追加します。
説明文終了