投稿者が理由を説明したので、大きな改訂版& T:Foo;問題ではなかった
この警告の起源は、ややばかげて複雑です。
調査の後、我々はComicSansMSも掲載マイクロソフトから次を見つける:テンプレート関数がインスタンス化されると、それが管理または非管理されている場合
、テンプレートの定義時のプラグマ状態が決定されます。
ファンクションテンプレート用です。使用しているクラステンプレートではありません。
実際、この関数テンプレートのインスタントメッセージは、慎重に関連するです。しかし、この警告が動作する独特の方法は、コンパイルプロセスと関係しています。
コンパイラは、実際にあなたが管理の#pragmaでファイルを終了したときにUsesFunPtrのctorのを呼び出して使用するためのマネージコードを生成しています。それは、そこにいくつかの管理されていないコードがあることを警告します。ここでは、その理由を詳細に分析します。
サンクは、基本的に特定のvtable呼び出しを中心としたラッパー関数です。ウィキペディアには、この件に関してまともな記事があります。サンクを生成する理由は、関数のアドレス(& T :: Foo)を取っているためです。
ファイルの最後の行である場合は、この:
#pragma unmanaged
が、それはあなたがそのオブジェクトにマネージコードとアンマネージコードを混在している場合でも、文句を停止します。これは、フロントエンドとバックエンドの間の接続が切断されているためです。上のコードを最後の#pragmaコマンドでコンパイルします。
この警告は、コンパイル時の警告ではありません。その後、
void DoIt()
{
long a;
long long b;
b = 4;
a = b;
UsesFunPtr<Interface> d;
}
あなたは「コンパイルx.cpp」の際に切り捨てについての警告が表示されます:それはあなたがそうのようなあなたのドイト()関数を修正した場合は、「...コードの生成」それが言うとき、コンパイル後に来ますコード生成フェーズ(Generating code ...)に移動します。このフェーズでは、この質問に関する警告が表示されます。
コンパイラは、種類のJavaバイトコードと同様に、等、解析し、中間バイナリ形式ソートの作成フロントエンドです。コードジェネレータは、このバイトコード(この場合はWindows x86)からターゲットプラットフォーム上に実際の出力を作成するバックエンドです。
バックエンドがコードを保持するまで、最適化は行われません。サンクは最適化の一種であるため、警告を出すのはコンパイラではなく、コンパイルされたILコードを取るコードジェネレータです。それは私が知っているどのような方法でもオフにすることができる最適化ではありません。これは標準的な方法です。
しかし、そのテンプレートをインスタンス化するのはコンパイラです。バックエンドはちょうど完全なクラスを見て、それを理解するように言われています。
管理対象C++/CLIのコンパイル時に違いがあります。時にコンパイラは、リンク時コード生成と呼ばれるものを使用することができます。これが起こると、リンカはバックエンドを呼び出すリンカです。 (様々な理由で)不可能な場合、コンパイルの一般的なプロセス(フロントエンド→バックエンド→リンカー)を経ます。
#pragmaは、受け取った順にILに渡されます。これは、#pragma managedが行われた後、UsesFunPtrの関数サポートコードが実際には "最後に追加されました"ことを示しているようです。だからあなたのコードは、管理対象外の空間にあるにもかかわらず、コードジェネレータは、見ている:
- アンマネージドオブジェクトの定義を、あなたが書いていないクラスについて
- マネージド
- 追加サポートコードを使用すると、それは他のオブジェクトファイルとのインタフェースとは関係ありません:vtableの作成やコピーなどそれを取得ILは、実際には2つを接続していないため
ジェネレータは、あなたが完全管理またはアンマネージコードであることを、そのUsesFunPtrのctorの、あるいはクラスを意味している場合区別する方法はありません。それは、(プラグマによって)管理されていない、それを作成し、その上で動作し、管理された空間で(プラグマによって)サンクを生成する関数をサポートする関数を参照します。それは接続を伝えることはできません。その#pragmaをそこに置くので、最後に#pragmaを見ただけです。生成されたサポートコードが管理されます。
#pragma unmanagedを最後に置くと、テンプレートを混在させた管理コードがあっても、その警告は表示されません。これは、コードがアンマネージドとしてコンパイルされているため、サンクは問題にならないからです。
これを合計する方法は?最後に#pragma managedは、フロントエンドとバックエンドの間で誤った通信(または間違った前提ですか?)を引き起こし、バックエンドはそれに不満を持ちます。
ウィー、それは楽しいものでした!
私はprgamaのものがバグかもしれないことに同意しますが、&T :: Fooに何も間違っているとは確信していません。それは何もしませんが、構文は有効です。ここでの目的は、問題を解明することです。実際のコードはstd :: bind(&T :: Foo、instanceOfT)です。これは完全に有効で呼び出し可能な関数オブジェクトになります。そこにコンパイラのバグはありません。 – stijn
@stijnハ、私はあなたの実際のコードで、std :: bindを使って提案したことをやっただけです。それはこれを知るのを助けていたでしょう。その場合、これを修正するために、Microsoftにバグレポートを提出します。彼らはそれをいかに速く修正するかはかなりクールです。たとえば、関連する修正プログラム:http://connect.microsoft.com/VisualStudio/feedback/details/122489/warning-c4793-and-pragma-unmanaged私は私の答えを改めるつもりです。 –
+1この予期しない複雑な問題に対する優れた答え。 – ComicSansMS