C++0x、コンパイラフックおよびハードコードされた言語機能
-
13-09-2019 - |
質問
C++0x の新機能のいくつかについて少し興味があります。特に 範囲ベースの for ループ そして 初期化子リスト. 。どちらの機能も、正しく機能するにはユーザー定義のクラスが必要です。
出会った この郵便受け, 、そしてトップの回答は役に立ちました。それが完全に正しいかどうかはわかりません (私はおそらく完全に誤解しているだけです。最初の回答の3番目のコメントを参照してください). 。による 現在の仕様 初期化子リストの場合、ヘッダーは 1 つの型を定義します。
template<class E> class initializer_list {
public:
initializer_list();
size_t size() const; // number of elements
const E* begin() const; // first element
const E* end() const; // one past the last element
};
これは仕様で確認できます。Ctrl + F だけです。 'クラス初期化子リスト'.
のために = {1,2,3}
暗黙的にキャストされる initializer_list
クラス間の関係について、コンパイラはある程度の知識を持っている必要があります。 {}
そして initializer_list
. 。何かを受け取るコンストラクターはないため、私の知る限り、initializer_list はコンパイラーが実際に生成するものにバインドされるラッパーです。
それは同じです for( : )
ループも機能するためにユーザー定義型を必要とします (ただし、仕様によれば、配列と初期化子リストのコードを必要としないように更新されています)。ただし、初期化子リストには次のものが必要です <initializer_list>
, 、つまり、プロキシによるユーザー定義のコード要件です)。
ここでこれがどのように機能するかを完全に誤解していますか?これらの新機能は実際にはユーザー コードに非常に大きく依存していると考えるのは間違いではありません。機能が中途半端で、機能全体をコンパイラに組み込むのではなく、半分はコンパイラによって実行され、半分はインクルードで実行されているように感じられます。その理由は何でしょうか?
編集: 「ユーザー コードに大きく依存する」ではなく、「コンパイラ コードに大きく依存する」と入力しました。これは私の質問を完全に打ち消してしまったと思います。私が混乱しているのは、コンパイラーに組み込まれている新機能に関するものではなく、ユーザー コードに依存するコンパイラーに組み込まれている機能です。
解決
これらの新機能は実際にはコンパイラ コードに非常に大きく依存していると考えるのは間違いではありません。
これらはコンパイラに非常に依存しています。ヘッダーを含める必要があるかどうかに関係なく、実際にはどちらの場合でも、現在のコンパイラでは構文が解析エラーになります。の for (:)
は今日の標準には完全には適合しません。許容される唯一の構成要素は次のとおりです。 for(;;)
機能が中途半端で、機能全体をコンパイラに組み込むのではなく、半分はコンパイラによって実行され、半分はインクルードで実行されているように感じられます。その理由は何でしょうか?
このサポートはコンパイラーに実装する必要がありますが、それが機能するにはシステムのヘッダーを組み込む必要があります。これにはいくつかの目的があります。初期化リストの場合、型 (コンパイラ サポートへのインターフェイス) をユーザーのスコープに取り込んで、それを使用できるようにします (C での va_args がどのようになっているかを考えてください)。範囲ベースの for (単なる構文糖衣) の場合、コンパイラーがその魔法を実行できるように、Range をスコープに組み込む必要があります。標準では次のように定義されていることに注意してください。 for ( for-range-declaration : expression ) statement
(草案では[6.5.4]/1)と同等:
{
auto && __range = ( expression );
for ( auto __begin = std::Range<_RangeT>::begin(__range),
__end = std::Range<_RangeT>::end(__range);
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
配列や STL コンテナのみで使用したい場合は、 Range
(C++0x の意味ではありません) という概念ですが、構文をユーザー定義クラス (独自のコンテナー) に拡張したい場合、コンパイラーは既存の構文に簡単に依存できます。 Range
テンプレート (独自の専門分野を含む)。定義されているテンプレートに依存するメカニズムは、コンテナー上で静的インターフェイスを要求することと同じです。
他のほとんどの言語は、通常のインターフェイス (コンテナーなど) を必要とし、それに対して実行時ポリモーフィズムを使用する方向に進んでいます。これを C++ で行う場合、STL コンテナは共通のベースやインターフェイスを共有しておらず、ポリモーフィックに使用する準備ができていないため、STL 全体で大規模なリファクタリングを行う必要があります。
存在する場合、現在の標準は適用されません。 生焼けの 出るまでに。
他のヒント
それは単なる構文糖です。コンパイラは、指定された構文構造を、標準の型/シンボル名を直接参照する同等の C++ 式に拡張します。
最新の C++ コンパイラーが言語と「外部世界」の間に持つ強力な結合はこれだけではありません。例えば、 extern "C"
これは、C のリンク モデルに対応するためのちょっとした言語ハックです。スレッドローカル ストレージを宣言する言語指向の方法は、機能するために多くの RTL ハッキングに暗黙的に依存します。
あるいはCを見てください。経由で渡された引数にアクセスするにはどうすればよいですか ...
?標準ライブラリに依存する必要があります。しかし、これは C コンパイラがスタック フレームをどのように正確にレイアウトするかに非常に大きく依存する魔法を使用します。
アップデート:
どちらかといえば、ここで C++ が採用したアプローチは、代替手段 (つまり、 本質的な 言語に組み込まれたコレクション型または範囲型。代わりに、ベンダー定義の範囲タイプを介して実行されます。実際には、可変個引数とそれほど違いはありません。可変個引数も、ベンダー定義のアクセサー マクロがなければ同様に役に立ちません。