9

私はC++0xの計画を検討していてstd::initializer_list、ユーザークラスに初期化子リストを実装することに気づきました。このクラスは、それ自体を使用せずに、または「コンパイラの魔法」を使用せずにC++で実装することはできませんでした。initializer_list可能であれば、実装に使用した手法を使用して独自のクラスに初期化子リストを実装できるため、必要ありません。

他にどのようなクラスが機能するために何らかの形の「コンパイラマジック」を必要としますか?サードパーティライブラリで実装できなかった標準ライブラリのクラスはどれですか?

編集:多分実装される代わりに、私はインスタンス化されたと言うべきです。このクラスが言語機能と直接リンクしているという事実はさらに重要です(初期化子リストはinitializer_list)なしでは使用できません。

C#と比較すると、私が疑問に思っていることが明らかになるかもしれません。IEnumerableとIDisposableは、実際には言語機能にハードコードされています。Stroustrupはすべてをライブラリに実装可能にしようとしたので、私は常にC++にはこれがないと思っていました。それで、言語機能に密接に結びついている他のクラス/タイプはありますか?

4

8 に答える 8

5

私が考えることができた他の唯一のものは、typeidによって返されるtype_infoクラスでした。私の知る限り、VC ++は、コンパイル時に必要なすべてのtype_infoクラスを静的にインスタンス化し、実行時にvtableの値に基づいてポインターをキャストすることでこれを実装します。これらはCコードを使用して実行できることですが、標準に準拠した方法や移植可能な方法では実行できません。

于 2008-10-29T16:47:53.130 に答える
5

std::type_info単純なクラスですが、それを設定するには次のものが必要typeinfoです: コンパイラ構造。

同様に、例外は通常のオブジェクトですが、例外をスローするにはコンパイラの魔法が必要です (例外はどこに割り当てられますか?)。

std::initializer_list私にとっての疑問は、「コンパイラの魔法なしで sにどれだけ近づくことができるか?」ということです。

wikipediaを見るとstd::initializer_list<typename T>、配列リテラルによく似たもので初期化できます。std::initializer_list<typename T>配列を取る変換コンストラクター (つまり、 の単一の引数を取るコンストラクターT[])を指定してみましょう。

namespace std {
     template<typename T> class initializer_list {
         T internal_array[];
         public:
         initializer_list(T other_array[]) : internal_array(other_array) { };

         // ... other methods needed to actually access internal_array
     }
}

同様に、 a を使用するクラスstd::initializer_listは、単一の引数を取るコンストラクstd::initializer_listター (別名変換コンストラクター)を宣言することによってこれを行います。

struct my_class {
    ...
    my_class(std::initializer_list<int>) ...
}

だから行:

 my_class m = {1, 2, 3};

コンパイラーに次のように考えさせます: 「 のコンストラクターを呼び出す必要がありmy_classます。C ++では2つの暗黙的なユーザー定義の変換を連鎖させることはできないと私に言う前の答え)。my_classstd::initializer_list<int>int[]int[]std::initializer_list<int>my_class

それで、これはどれくらい近いですか?まず、初期化子リストのいくつかの機能/制限がありません。私が強制しないことの 1 つは、イニシャライザ リストは配列リテラルでしか構築できないということです。一方、initializer_list既に作成された配列も受け入れます。

int arry[] = {1, 2, 3};
my_class = arry;

さらに、右辺値参照をいじることはありませんでした。

最後に、このクラスは、コンパイラが 2 つのユーザー定義の変換を暗黙的に連鎖させた場合にのみ、新しい標準が示すように機能します。これは通常のケースでは特に禁止されているため、この例ではコンパイラの魔法が必要です。しかし、私は、(1) クラス自体は通常のクラスであり、(2) 関連する魔法 (「配列リテラル」初期化構文を強制し、2 つのユーザー定義の変換を暗黙的に連鎖できるようにする) は、見た目よりも少ないと主張します。一見。

于 2008-10-30T00:14:19.937 に答える
1

標準ライブラリのすべてのクラスは、定義上、C++で実装する必要があります。それらのいくつかは、いくつかのあいまいな言語/コンパイラ構造を隠しますが、それでも言語機能ではなく、その複雑さの単なるラッパーです。

于 2008-10-29T16:58:10.597 に答える
1

定義されたポイントでランタイムが「フックする」ものはすべて、仮想言語「C++、それを除く」で移植可能なライブラリとして実装できない可能性があります。

たとえば、<cstdlib> の atexit() は純粋にライブラリとして実装することはできないと思います。C++ には、終了シーケンスの適切なタイミングで、つまりグローバル デストラクタの前に確実に呼び出されるようにする方法が他にないためです。 .

もちろん、C の機能はこの質問には「数えない」と主張することもできます。その場合、まったく同じ理由で、 std::unexpected がより良い例かもしれません。存在しない場合、コンパイラによって発行された例外コードをいじらずに実装する方法はありません。

[編集: 質問者が、標準ライブラリのどの部分を実装できないかではなく、どのクラスを実装できないかを実際に尋ねていることに気付きました。したがって、実際には、これらの例は質問に厳密には答えていません。]

于 2008-10-29T23:51:01.120 に答える
1

MSalter はコメントで printf/cout/stdout を指摘しています。それらのいずれかを他のいずれかの観点から実装することはできますが (私は思います)、OS の呼び出しやコンパイラの魔法がなければ、それらのセット全体を一緒に実装することはできません。

  1. これらはすべて、プロセスの標準出力ストリームにアクセスする方法です。バイトをどこかに詰め込む必要があります。これらがない場合、それは実装固有です。別のアクセス方法を忘れていない限り、ポイントは、実装固有の「魔法」以外では標準出力を実装できないということです。

  2. それらは実行時に「魔法の」動作をしますが、これは純粋なライブラリでは完全には模倣できないと思います。たとえば、コンパイル単位間の静的初期化の順序が定義されていないため、cout を構築するために静的初期化を使用することはできません。stdout は fd 1 であるため、おそらくより簡単です。したがって、それをサポートする任意の装置は、それが表示されたときに渡される呼び出しによって作成できます。

于 2008-10-30T15:38:13.160 に答える
1

C++ を使用すると、コンパイラは未定義の動作を定義できます。これにより、非標準の C++ で標準ライブラリを実装できます。たとえば、「onebyone」は atexit() について疑問に思います。ライブラリの作成者は、移植性のない C++ をコンパイラで問題なく動作させるコンパイラに関する事柄を想定できます。

于 2008-10-30T10:03:49.637 に答える
0

再びC++0xから、スレッドは仮想言語「C ++ 0x、スレッドを除くすべての標準ライブラリ」でポータブルライブラリとして実装できないと思います。

[編集:明確にするために、「スレッドの実装」が何を意味するかについては、いくつかの意見の相違があるようです。この質問の文脈で私が理解していることは次のとおりです。

1)C ++ 0xスレッド仕様を実装します(それが判明したものは何でも)。C ++ 0xに注意してください。これは、私と質問者の両方が話していることです。POSIXなどの他のスレッド仕様はありません。

2)「コンパイラマジック」なし。これは、実装作業を支援するためにコンパイラに何も追加しないこと、および非標準の実装の詳細(特定のスタックレイアウト、スタックを切り替える手段、または時限割り込みを設定するための非ポータブルシステムコールなど)に依存しないことを意味します)特定のC++実装でのみ機能するスレッドライブラリを作成します。言い換えれば、純粋でポータブルなC++です。シグナルとsetjmp/longjmpは移植性があるので使用できますが、私の印象ではそれだけでは不十分です。

3)C ++ 0xスレッド仕様のすべての部分が欠落していることを除いて、C++0xコンパイラーを想定します。欠落しているのがデータ構造(join()または同等のものによって使用される終了値と同期プリミティブを格納する)だけであるが、スレッドを実装するコンパイラの魔法が存在する場合は、明らかにそのデータ構造をサードパーティとして追加できますポータブルコンポーネント。しかし、どのC ++ 0x標準ライブラリクラスがそれらをサポートするためにコンパイラの魔法を必要とするかという質問があったとき、それは一種の鈍い答えです。IMO。]

于 2008-10-29T23:41:43.760 に答える
0

このスコアではかなり安全だと思います。C++ は、ほとんどの場合、C を取り巻く抽象化の厚いレイヤーとして機能します。C++ はC 自体のスーパーセットであるため、コア言語プリミティブはほとんどの場合、sans-classes (C スタイル) で実装されます。言い換えれば、Objectコンパイラにハードコードされた特別な意味を持つクラスである Java のような多くの状況を見つけることはありません。

于 2008-10-29T17:06:39.487 に答える