11

クラスの2つの静的メンバーを公開するVS2010 C#で構築された単純な.NET dllがあります

public class Polygon
{
    public static void Test(int test) {}
    public static void Test(List<int> test) {}
}

次に、VS2010 C++ からコンソール アプリを作成し、この関数を _tmain の上に追加しました。

extern "C" void TestMe()
{
    Polygon::Test(3);
}

参照を追加してコンパイルすると、このエラーが発生します

1>WierdError.cpp(9): error C2526: 'System::Collections::Generic::List<T>::GetEnumerator' : C linkage function cannot return C++ class 'System::Collections::Generic::List<T>::Enumerator'
1>          with
1>          [
1>              T=int
1>          ]
1>          WierdError.cpp(9) : see declaration of 'System::Collections::Generic::List<T>::Enumerator'
1>          with
1>          [
1>              T=int
1>          ]
1>          WierdError.cpp(9) : see reference to class generic instantiation 'System::Collections::Generic::List<T>' being compiled
1>          with
1>          [
1>              T=int
1>          ]

私の観察のいくつか:

  • extern "C" を削除すると、正常にコンパイルされます
  • Test(List<int> test)名前を変更すると、正常にコンパイルされますTest2(List<int> test)

私の質問は、何がうまくいかないのか、C++ 側からそれを修正する方法です。

私の現在の回避策は、C# でメソッドの名前を変更することですが、これを行う必要はありません。C++ プロジェクトに欠けている可能性のある設定があると感じています。

編集:

C++ でより良い回避策を見つけました。別の関数で .NET 呼び出しをラップできるようです。

void wrapper()
{
    Polygon::Test(3);
}

extern "C" void TestMe()
{
    wrapper();
}

これをしなければならないのはばかげているようですが、コンパイラのバグなのだろうか? 私が怖いのは、そのようなメソッドを使用していて、C# 開発者が後でそのような静的メソッドを追加して C++ ビルドを壊してしまうのではないかと心配しなければならないことです。

4

1 に答える 1

6

ここでは、次の理由でワイルドショットを撮ります。

コンパイル中に、MSVC の C++ コンパイラは、がクラス内でextern "C" function TestMe()関数を呼び出していることを確認します。コンパイラにとって不完全な型です。コンパイラは、関数が不完全な型を返しているのか、何かを返しているのかを認識できないと思います。型がプレーンな C スタイルの POD 型ではないことが判明した場合に備えて、その時点でエラーを返す必要があると判断します。Test()PolygonPolygonPolygon::Test(3)

上記は、(7.5/9「リンケージ仕様」) C++ 標準が言うように、MSVC の一部に関する合理的な仮定のようです。

「C++から他の言語で定義されたオブジェクトへのリンク、および他の言語からC++で定義されたオブジェクトへのリンクは、実装定義および言語依存です。2つの言語実装のオブジェクトレイアウト戦略が十分に類似している場合にのみ、そのようなリンクを実現できます。」

extern Cこれは、リンケージ仕様を削除するか、Cstyle 関数への呼び出しを置き換えると、エラーが消えることを説明します。

于 2011-06-16T17:50:56.563 に答える