9

次の点を考慮してください。

namespace N {
    extern "C" void f();
}

void g() {
    N::f();
}

このコードは、名前空間内で C リンケージを持つ外部関数を宣言します。これにより、プライベート名前空間からそのような関数を参照できるようになり、通常のグローバル外部宣言によって引き起こされる名前空間の汚染を回避できます。また、クライアント コードは、ベンダー提供のヘッダー インクルードに起因する可能性があるグローバル名前空間であっても、競合することなく同じ関数に対して他の (できれば互換性のある) 宣言を発行できます。

私はしばしば、C と C++ の両方で同様の構造を使用して、一部のライブラリで提供される不適切な記述または競合するヘッダー ファイルからコンパイルを分離します。extern(C では、これは関数スコープで必要な宣言を発行することによって達成されます。これは、関数スコープで許可されていないリンケージ宣言がなければ、C++ でも可能です。) これは、明確に定義されたベンダー提供のヘッダー ファイルに依存する必要のない ABI。

通常の C++ リンケージを持つ関数またはメソッドで同じことを行うことは可能ですか? つまり、プライベート名前空間内 (または任意の種類のローカル スコープ) で C++ リンケージを使用して外部関数を宣言しますが、別の名前空間内で実際に定義された関数を参照する可能性がありますか?

意図した機能 (疑似コード):

namespace N {
    // Actually should link with P::f() (and not N::f()).
    extern "C++" void f();
}

void g() {
    N::f(); // P::f();
}

これは明らかにソース ファイルの問題ではありません (ヘッダー ファイルとは対照的に)。その場合、名前空間の汚染は問題にならないからです。したがって、この質問は主に、ライブラリ ヘッダー ファイル内の宣言の分離に関するものです (テンプレートおよびインライン関数内で使用するため)。

コンパイラ固有のソリューションは大歓迎です (MSVC と GCC が対象です)。

例:ライブラリが呼び出され、名前空間Lib1内のすべてを宣言したいとします。Lib1

// Lib1.hpp
namespace Lib1 {
    class Class1;
    void func1();
    // ...
}

ここで、私のライブラリが別のライブラリ を参照しているとしLib2ます。これは、他の誰かによって提供された C ライブラリです。

/* Lib2.h */
#ifdef __cplusplus
extern "C" {
#endif

struct Struct2;
void func2();
/* ... */

#ifdef __cplusplus
}
#endif

私のライブラリでは、何らかの理由でこれが必要な場合は、エンティティをまったくLib2含めることなく参照できます。Lib2.h

// Lib1.hpp
namespace Lib1 {
    extern "C" void func2();

    inline void inlineX() {
        func2();
    }
}

同時に、クライアント コードには、Lib1.hppLib2.h(C++ に適していることを考慮して) の両方をコンフリクトなしで自由に含めることができます。

ここでLib3、C++ ライブラリであり、Lib3名前空間でエンティティを宣言する 3 番目のライブラリ があるとします。

// Lib3.hpp
namespace Lib3 {
    class Class3;
    void func3();
    // ...
}

Lib3と同じように関係する方法はありLib2ますか?つまり:Lib3内部のエンティティを参照しLib1.hpp、含めずに、Lib3.hppクライアント コードに両方を含めることを許可Lib1.hppし、面倒なことはLib3.hppありませんか?

Lib1で宣言されている場合:

// Lib1.hpp
namespace Lib3 {
    void func3();
}

namespace Lib1 {
    inline void inlineY() {
        Lib3::func3();
    }
}

Lib1.hpp次に、クライアント コードにとの両方が含まれている場合、競合が発生する可能性がありますLib3.hpp。宣言が同一であるこの単純な例では確かにそうではありませんが、実際の状況での微妙な違いにより、基礎となる ABI が同じであっても、構文レベルで警告またはエラーがトリガーされる可能性があります。これは、Lib1名前空間の外では何も宣言しないという前提に違反しているためです。

これが質問を理解するのに役立つことを願っています。

4

1 に答える 1