6

多くのレガシー コードと、C で記述されたいくつかの外部ライブラリを含む、大きくて古い C++ アプリケーションがあります。これらのライブラリは、バグが見つかり、ベンダーがパッチを提供した場合にのみ更新されることはほとんどありません。これは先週 1 つのライブラリで発生し、新しいバージョンを統合すると、ライブラリをローカルで変更しないと (以前のバージョンで行ったようです)、ビルドが次のエラー メッセージで中断することがわかりました。

non-local function ‘static E* MyCls::myFct(<anonymous struct>*)’ uses anonymous type

これは、ライブラリが次のような多数のハンドル タイプを宣言しているためです。

#define _Opaque struct {unsigned long x;} *

typedef _Opaque    Handle;
typedef _Opaque    Request;

一部のクラスの関数シグネチャで使用します。

class MyCls {
public:
    static void* myFct(Handle handle);
    ...
}

_Opaque 構造体には名前がないため、コンパイラは関数の適切な名前マングル名を作成できないため、上記のエラーが発生します。

これに対する現在の回避策は、構造体に明示的に名前を付けて、ライブラリ ヘッダー ファイルにパッチを適用することです。

//#define _Opaque struct {unsigned long x;} * //Replaced by typedef below!
typedef struct __Opaque {unsigned long x;} * _Opaque;

可能であればライブラリに触れたくないので、これは明らかに悪いことです。もう1つのさらに悪いオプションはvoid*、すべての関数シグネチャで型を変換し、それぞれの型にキャストし直すことです。そして、影響を受けるすべての関数を純粋な C で書き直すという最悪の選択肢があります...

だから、私の質問は次のとおりです。ライブラリにパッチを適用するよりも良いオプションはありますか? 私が見落としている簡単な解決策はありますか?これを解決する最善の方法は何ですか?

4

4 に答える 4

3

これは、行を最小限に変更するだけで実現できます#define。7.1.3:8のルールを利用して、宣言によってそのクラスタイプ(または列挙型)として宣言された最初のtypedef-nameを使用して、クラスタイプ(または列挙型)リンケージ目的のみ

#define MAKE_DUMMY2(line) dummy_ ## line
#define MAKE_DUMMY(line) MAKE_DUMMY2(line)
#define _Opaque struct {unsigned long x;} MAKE_DUMMY(__LINE__), *

これによりHandleRequestリンクなどが最小限に抑えられます。

于 2012-08-13T13:19:12.110 に答える
1

インターフェイスのメソッドを変更する場合は、次の方法よりもわずかに優れていますvoid *

struct CHandle {
    void *p;
    CHandle(void *p): p(p) { }
};
struct CRequest {
    void *p;
    CRequest(void *p): p(p) { }
};

static CHandle make(Handle handle) { return CHandle(handle); }
static Handle get(CHandle handle) { return static_cast<Handle>(handle.p); }
static CRequest make(Request request) { return CRequest(request); }
static Request get(CRequest request) { return static_cast<Request>(request.p); }

ここでは、CHandleリンケージCRequestがあり、メソッド シグネチャで使用できます。と のオーバーロードにmakeget内部リンケージがあるため、匿名型とやり取りできます。関数でさえ、これをヘッダーに入れることができstaticます。

MyCls::myFctたとえばがライブラリを呼び出すときに、パラメータを でラップしget、値を で返すように、コードを変更する必要がありますmake

于 2012-08-13T13:47:40.813 に答える
1

これらの要素を単純に含む新しい型を宣言することで、名前を導入できます。これらのタイプをパラメーターに使用します。

namespace MON {
struct t_handle {
  Handle handle;
};

class MyCls {
public:
    static void* myFct(t_handle handle);
    ...
};
}
于 2012-08-13T12:08:24.120 に答える
0

これはうまくいくようです:

class MyCls {
  public:
    typedef _Opaque MHandle;
    static void* myFct(MHandle handle) {
      return 0;
    }   
};
于 2012-08-13T12:10:30.140 に答える