web-dev-qa-db-ja.com

C ++で「関数を毒する」とはどういう意味ですか?

Scott Schurrの講演の最後に "CppConでconstexpr"を紹介しています 、彼は「関数をポイズニングする方法はありますか?」次に、彼はこれを(非標準的な方法ではあるが)行うことができると説明します。

  1. throwconstexpr関数に入れる
  2. 未解決のextern const char*の宣言
  3. extern内の未解決のthrowを参照する

私はここの深さから少し外れていると感じていますが、私は興味があります:

  • 「機能を中毒する」とはどういう意味ですか?
  • 彼が概説する技術の意義/有用性は何ですか?
95

一般に、関数を使用できないようにすることを指します。プログラムでの動的割り当ての使用を禁止する場合は、malloc関数を「ポイズニング」して使用できないようにすることができます。

ビデオでは、彼はより具体的な方法でそれを使用しています。彼が関数のポイズニングについて話すときに表示されるスライドを読むと、「コンパイル時のみを強制する方法?」

したがって、彼は実行時に関数を「中毒」して呼び出し不可能にすることについて話しているので、定数式ではonly呼び出し可能です。テクニックは、コンパイル時のコンテキストで呼び出されたときに決してとられない関数にブランチを持ち、そのブランチにエラーを引き起こす何かを含めることです。

throw式は、関数のコンパイル時の呼び出し中に到達しない限り、constexpr関数で許可されます(コンパイル時に例外をスローできないため、本質的に動的な操作です。メモリの割り当てなど)。そのため、未定義のシンボルを参照するthrow式は、コンパイル時の呼び出し中には使用されず(コンパイルに失敗するため)、実行時に使用できません。これは、未定義のシンボルがリンカーエラーを引き起こすためです。

未定義のシンボルは、関数のコンパイル時の呼び出しで「odr使用」されないため、実際にはコンパイラはシンボルへの参照を作成しないため、未定義であってもかまいません。

それは便利ですか?彼はhowを示していますが、必ずしもそれが良いアイデアだとか広く有用だとか言っているわけではありません。何らかの理由でそれを行う必要がある場合、彼のテクニックはあなたの問題を解決するかもしれません。必要がない場合は、心配する必要はありません。

mightが有用な理由の1つは、一部の操作のコンパイル時バージョンが可能な限り効率的でない場合です。 constexpr関数で許可される式の種類には制限があります(特にC++ 11では、C++ 14では一部の制限が削除されました)。したがって、計算を実行するための関数の2つのバージョンがあります。1つは最適ですが、constexpr関数では許可されない式を使用し、もう1つは有効なconstexpr関数ですが、実行時に呼び出されるとパフォーマンスが低下します時間。最適ではないものをポイズニングして、ランタイムコールに使用されないようにし、ランタイムコールにより効率的な(constexpr以外の)バージョンが使用されるようにします。

N.B.コンパイル時に使用されるconstexpr関数のパフォーマンスは、とにかく実行時のオーバーヘッドがないため、それほど重要ではありません。コンパイラに余分な作業をさせてコンパイルを遅くするかもしれませんが、実行時のパフォーマンスコストはかかりません。

105
Jonathan Wakely

識別子の「中毒」は、「中毒」の後の識別子への参照がハードコンパイラエラーであることを意味します。この手法は、たとえば、強力な非推奨に使用できます(関数IS非推奨、使用しないでください!)。

GCCには伝統的にこのためのプラグマがありました:#pragma GCC poison

17
SergeyA