1. ホーム
  2. c++

[解決済み】なぜC++にはリフレクションがないのですか?

2022-03-25 22:23:19

質問

ちょっと奇抜な質問です。私の目的は、言語設計の決定を理解することと、C++におけるリフレクションの可能性を確認することです。

  1. なぜC++言語委員会は言語にリフレクションを実装する方向に進まなかったのでしょうか?仮想マシン上で動作しない言語(javaなど)では、リフレクションは難しすぎるのでしょうか?

  2. もし、C++にリフレクションを実装するとしたら、どんな課題がありますか?

エディタが書きやすくなる、プログラムコードが小さくなる、単体テスト用のモックを生成できるなど、リフレクションの用途はよく知られているかと思います。しかし、リフレクションの用途についてもコメントしてもらえるとうれしいです。

どのように解決するのか?

C++のリフレクションには、いくつかの問題があります。

  • C++委員会はかなり保守的で、成果が上がると確信できない限り、急進的な新機能に時間を費やすことはありません。(.NETのアセンブリに似たモジュールシステムを追加する提案がなされ、それがあればいいという一般的なコンセンサスは得られていると思いますが、現時点での最優先事項ではなく、C++0xのかなり後まで延期されました。この機能を実現するための動機は #include システムで、少なくともいくつかのメタデータを使用できるようになります)。

  • 使わないものにはお金を払わない。 を使用します。これは、基本中の基本です。 C++の根底にある設計思想です。 なぜ私のコードに メタデータが必要でないなら、どうすればいいのでしょうか? さらに、メタデータを追加することで コンパイラを阻害する可能性があります。 最適化する。なぜ、そのような を、自分のコードに反映させることができます。 そのメタデータは?

  • それがもうひとつの大きなポイントになります。 C++は 非常に 保証はほとんどない は、コンパイルされたコードについて コンパイルされたコードは コンパイラは のであれば、ほとんど何でもありです。 結果としての機能は が期待されます。例えば クラスが実際に ある . コンパイラは、それらを最適化し、インライン化することができます。 を行うことができ、それは 頻繁に行われます。 単純なテンプレートコードでも かなりの数のテンプレート のインスタンス化です。C++の標準 ライブラリ を頼りにしています。 この積極的な の最適化を行います。ファンクターは のオーバーヘッドが大きい場合、パフォーマンスが低下します。 のインスタンス化とデストラクションを行います。 オブジェクトを最適化することができます。 operator[] は、ベクトル上の 配列インデックスのパフォーマンス というのは、演算子全体を インライン化され、完全に削除されました。 をコンパイルされたコードから削除する必要があります。C#とJava について多くの保証をしています。 を出力します。もし私が C# でクラスを作成した場合、そのクラスは は 存在する を作成します。 たとえ一度も使わなくても たとえすべての そのメンバ関数の呼び出しは インライン化されます。クラスは が存在し、リフレクションがそれを見つけることができます。 である。この問題の一部は、C#のおかげで緩和されました。 バイトコードにコンパイルする。 JITコンパイラが できる 削除 クラス定義とインライン 関数が好きな場合は、たとえ C#の初期コンパイラはできません。C++では コンパイラは1つしかなく、しかも は効率的なコードを出力しなければなりません。もし メタデータを検査することが許可された C++の実行ファイルには、次のようなものがあります。 定義されているすべてのクラスが表示されます。 つまり、コンパイラは 定義されたクラスをすべて保持すること。 必要ないものでも

  • そして、テンプレートです。 C++のテンプレートは 他の言語ではジェネリック すべての テンプレートのインスタンスを作成すると 新しい という型があります。 std::vector<int> とは完全に別のクラスです。 std::vector<float> . その結果 を使用することで、全体として多くの異なる型を プログラムです。何を反映させるか を参照してください。それは テンプレート std::vector ? しかし というのは、これは ソースコードの構成要素であり、何の意味もない 実行時に意味があるのか?それは 別のクラス std::vector<int>std::vector<float> . そして std::vector<int>::iteratorstd::vector<float>::iterator 同じ に対して const_iterator といった具合に。そして 一旦、テンプレートに足を踏み入れると メタプログラミングでは、すぐに 何百ものテンプレートをインスタンス化します。 これらはすべてインライン化され、削除されます。 また、コンパイラによって それらは の一部であることを除いては、意味がありません。 コンパイル時のメタプログラム。すべての これらの何百ものクラスは リフレクションに そうでなければならないでしょう。 なぜなら、そうでなければ私たちのリフレクションは を保証しないのであれば、意味がない。 ある . そして、副次的な問題として、テンプレート・クラスはインスタンス化されるまでは存在しない、ということがあります。を使うプログラムを想像してください。 std::vector<int> . リフレクションシステムは std::vector<int>::iterator ? 一方では、確かにそう思うかもしれません。このクラスは重要なクラスであり、その定義は std::vector<int> ということです。 する はメタデータに存在する。一方、もしプログラムが決して実際に 使用 このイテレータクラスのテンプレートは、その型がインスタンス化されたことがないため、コンパイラはそもそもクラスを生成していないことになります。また、ソースコードにアクセスする必要があるため、実行時に作成するのでは遅すぎます。

  • そして最後に、リフレクションは は、C++ではC#ほど重要ではありません。その理由は その理由は、やはりテンプレート メタプログラミングです。メタプログラミングは しかし、多くの場合 に頼ることになる。 を書くことができる。 同じことをするメタプログラム をコンパイル時に実行します。 boost::type_traits は、単純な の例です。あなたが知りたいのは、型 T ? その type_traits . C#の場合。 の後を追い回す必要があります。 型はリフレクションを使用しています。リフレクション を使用すると、まだ便利なことがあります。 のようなもの(私が考える主な用途。 メタプログラミングでは簡単に 自動生成される シリアライズコード)、しかし、それは には大きなコストがかかります。 C++では、他の言語ほど頻繁に必要ではありません。

編集する コメントを受けて

cdlearyです。 はい、デバッグシンボルは、実行ファイルで使用される型に関するメタデータを保存するという点で、似たようなことをします。しかし、デバッグシンボルは、私が説明したような問題にも悩まされています。リリースビルドをデバッグしようとしたことがある人なら、私が言っていることがわかると思います。ソースコードで作成したクラスが、最終的なコードではインライン化されてしまっているような、大きな論理的なギャップがあるのです。もしあなたがリフレクションを何か有用なことに使おうとするならば、より信頼性が高く、一貫性があることが必要でしょう。今のままでは、コンパイルするたびに型が消えたり、なくなったりしてしまいます。あなたが小さな小さなディテールを変更すると、コンパイラは、応答として、どの型がインライン化され、どの型がされないかを変更することを決定します。最も関連性の高い型がメタデータで表現されていることさえ保証されていないのに、どうやってそこから有用なものを抽出するのでしょうか?あなたが探しているタイプは、最後のビルドでは存在していたかもしれませんが、今はもうありません。そして明日、誰かが小さな無害な関数に小さな無害な変更をチェックインして、その型が完全にインライン化されない程度に大きくなり、再び戻ってくるでしょう。それはまだデバッグ用のシンボルとしては有用ですが、それ以上のものではありません。その条件でクラスのシリアライゼーションコードを生成しようとするのは嫌だなあ。

エヴァン・テラン もちろん、これらの問題は かもしれない 解決される。しかし、それは私の指摘1.に戻ってしまいます。C++委員会には、もっと重要だと思うことがたくさんあるのです。C++でいくつかの限定された反射(そしてそれは限定的なものでしょう)を得ることの利点は、他の機能を犠牲にしてそれに集中することを正当化するほど本当に大きいのでしょうか?QTのようなライブラリやプリプロセッサですでに(ほとんど)可能な機能をコア言語に追加することに、本当に大きな利点があるのだろうか。おそらく、しかし、そのようなライブラリが存在しない場合に比べれば、必要性はかなり低くなります。 しかし、あなたの具体的な提案については、私は、テンプレート上でそれを禁止することは、それを完全に無意味にしてしまうと信じています。たとえば、標準ライブラリでリフレクションを使うことができなくなります。どのようなリフレクションが、あなたが std::vector ? テンプレートは 巨大 C++の一部です。テンプレートで動かない機能は、基本的に意味がありません。

しかし、あなたの言うとおり、何らかの形でリフレクションを実装することは可能でしょう。しかし、それは言語の大きな変更になるだろう。今のところ、型は専らコンパイル時の構成要素である。コンパイラのために存在するのであって、それ以外には何もない。いったんコードがコンパイルされると、そこには クラスはありません。背伸びをすれば、関数がまだ存在すると主張できるかもしれませんが、実際には、ジャンプアセンブラ命令の束と、大量のスタックプッシュ/ポップがあるだけです。このようなメタデータを追加しても、あまり意味がないのです。

しかし、先ほど言ったように、コンパイルモデルを変更し、自己完結型のモジュールを追加し、選択した型のメタデータを保存し、他のモジュールがその型を参照できるようにする案があります。 #include s. 正直なところ、標準化委員会が、あまりに大きな変更であるという理由でこの提案を投げ出さなかったことに驚いているんだ。おそらく5~10年後でしょうか?)