5

テンプレート名にはリンケージ (3.5) があります。非メンバー関数テンプレートは、内部リンケージを持つことができます。他のテンプレート名には、外部リンケージが必要です。内部リンケージを持つテンプレートから生成されたエンティティは、他の翻訳単位で生成されたすべてのエンティティとは異なります。

キーワードを使った外部連携について知っている

extern "C"

元 :

extern "C" {   template<class T>  class X { };   }

しかし、彼らは テンプレートにCリンケージを持たないものとしました

上記のステートメントの実際の意味は何ですか?

誰でもこれを説明できますか?

4

4 に答える 4

26

extern "C"C言語リンケージを持つことを宣言します。これは外部連携内部連携とは異なります。デフォルトでは、C++ プログラム内のすべてに C++ 言語リンケージがありますが、指定することでこれを繰り返すことができますextern "C++"

外部リンケージとは、適切なヘッダーを含めるか、適切な宣言を提供することを前提として、個別にコンパイルされた他のソース ファイルに名前が表示されることを意味します。これにより、 で関数を定義fooa.cpp、 から呼び出すことができますb.cpp。C++ プログラムのネームスペース スコープのほとんどの名前には、外部リンケージがあります。例外は、内部リンケージを持つものとリンケージを持たないものです。を指定することで、何かを外部リンケージを持つものとして明示的にマークできますextern。これは とは異なりextern "C"ます。

内部リンケージは、名前が現在のコンパイル単位に固有であることを意味し、別のソース ファイルから変数または関数にアクセスすることはできません。宣言されたファイル スコープ変数と関数にはstatic、内部リンケージがあります。また、const定数式で初期化された名前空間スコープの整数変数には、デフォルトで内部リンケージがありますが、明示的にオーバーライドできますextern

最後に、ローカル変数とクラスにはリンケージがありません。名前は、宣言されている関数に対してローカルであり、その関数の外部からアクセスすることはできません。extern名前空間スコープで変数に本当にアクセスしたいことを示すために使用できます。

テンプレートはローカル スコープで定義することはできませんが、内部リンクまたは外部リンクのいずれかを持つことができます。

int i; // namespace scope variable has external linkage
extern int j; // explicitly mark j with external linkage
static int k; // k has internal linkage
int const n=42; // internal linkage
extern int const m=99; // external linkage

void foo(); // foo has external linkage; it may be defined in this source file or another
extern void foo(); // explicitly mark foo with external linkage
static void bar(); // bar has internal linkage, and must be defined in this source file

void foo(){} // definition of foo, visible from other source files
void bar(){} // definition of bar, not visible from other source files (internal linkage)

static void baz(){} // declare and define baz with internal linkage

template<typename T> void foobar(){} // foobar has external linkage
template<typename T>
static void foobaz(){} // foobaz has internal linkage

void wibble()
{
    int i; // local, no linkage
    extern int i; // references i, declared above with external linkage
}

extern "C"
{
    int i2; // namespace scope variable has external linkage, and "C" linkage
    extern int j2; // explicitly mark j2 with external linkage and "C" linkage
    static int k2; // k2 has internal linkage and "C" linkage
    int const n2=42; // internal linkage and "C" linkage
    extern int const m2=99; // external linkage and "C" linkage

    void foo2(); // foo2 has external linkage and "C" linkage
    static void bar2(); // bar2 has internal linkage and "C" linkage

    void foo2(){} // definition of foo2, still with external linkage and "C" linkage
    void bar2(){} // definition of bar2, still with internal linkage and "C" linkage

    static void baz(){} // declare and define baz with internal linkage
}

エラー メッセージは正しいです --- テンプレートはextern "C"リンケージを持つことができません。

基本レベルでは、テンプレートはextern "C"C と互換性がないため、リンケージを持つことはできません。特に、テンプレートは単一のクラスまたは関数を定義するだけでなく、同じ名前を共有するクラスまたは関数のファミリーを定義しますが、それらのテンプレート パラメータ。

指定された名前を持つ関数は 1 つだけ宣言できますextern "C"。名前マングリングについて考えると、これは理にかなっています。C では、関数fooは通常、fooまたは_fooシンボル テーブルで呼び出されます。C++ では、 のオーバーロードが多数ある可能性があるfooため、シグネチャはシンボル テーブルの「マングルされた」名前に組み込まれ、区別するために または または 他の何かを取得する場合が$3fooVありfoo$voidます。C++ では、指定されたプラットフォームの C スキームに従ってマークされた単一のオーバーロードがマングルされますが、他のオーバーロードは通常のマングルされた名前を保持します。foo(void)foo(int)extern "C"

テンプレートを宣言するにextern "C"は、すべてのインスタンス化を にする必要がありますextern "C"。これは、「指定された名前を持つ関数は 1 つだけにすることができるextern "C"」という規則に矛盾します。

structC にはs の名前マングリングはありませんがstruct、指定された名前を持つものは 1 つだけです。したがって、クラス テンプレートの禁止extern "C"も理にかなっています --- テンプレートは同じ名前のクラスのファミリを定義するため、どのクラスが C に対応しstructますか?

于 2010-08-08T22:29:49.393 に答える
9

あなたが書いた引用を注意深く読むだけで、内部リンケージを持つかもしれない非メンバー関数テンプレートを除いて、他のすべてのテンプレートが外部リンケージを持っていることに気付くでしょう。キーワードを追加する必要はなく、キーワードを追加することもできません。

リンケージの意味の説明は§3.5/2にあり、特に外部リンケージは次のように定義されています。

名前に外部リンケージがある場合、その名前が示すエンティティは、他の変換ユニットのスコープまたは同じ変換ユニットの他のスコープからの名前で参照できます。

テンプレートの非メンバー関数の内部リンクを強制するには、staticキーワードを使用できますが、他のテンプレートで同じことを行うことはできません。

template <typename T>
static void foo( T ) {}

匿名の名前空間を使用することで、内部リンケージと同様の効果を実現できることに注意してください。

内部リンケージ:§3.5/ 2

名前に内部リンクがある場合、その名前が示すエンティティは、同じ変換単位内の他のスコープからの名前で参照できます。

違いは、他の翻訳単位から参照できないことです。

namespace {
   template <typename T>
   class test {};
}

名前のない名前空間はリンケージを内部にしませんが、一意の名前空間にあるため、名前の衝突が発生しないようにします。この一意性により、他の変換ユニットからコードにアクセスできないことが保証されます。static名前のない名前空間は、キーワード§7.3.1.1/2のより良い代替手段と見なされます

名前空間スコープでオブジェクトを宣言する場合、staticキーワードの使用は非推奨になります(付録Dを参照)。unnamed-namespaceは、優れた代替手段を提供します

一方、あなたがあなたが言うとき:

キーワードを使用して外部リンケージについて知るextern "C"

あなたはそうしない。extern "C"外部リンケージの要求ではありません。仕様を読み直してください。extern "C"リンケージ仕様dlopenであり、ブロック内で「C」スタイルのリンケージを使用して、ファミリーなど、すでにそのように機能しているCコードまたはライブラリーと対話するようにコンパイラーに指示します。これは§7.5で説明されています

于 2010-07-27T08:08:18.077 に答える
2

extern "C" は、C++ 関数のシンボル名を C プログラムから使用するために変更するために使用されます。

C++ では、関数プロトタイプはシンボル名で「コード化」されています。これはオーバーロードの要件です。しかし、C では、そのような機能はありません。

extern "C" では、C プログラムから C++ 関数を呼び出すことができます。

extern "C" は探しているものではありません。

何をしたいのか説明していただけますか?

于 2010-07-27T06:22:06.550 に答える
1

更新された質問への回答は、元の質問に適用される回答で既に述べたように、extern "C"意味を誤解しているということです。

このシーケンスにより、次の関数またはブロックの言語リンケージextern "X"を languageに変更できます。外部リンクを意味するものではないため、元の前提は次のとおりです。X

キーワードを使った外部連携について知っているextern "C"

falseです。あなたはそれが何を意味するのか分かりません。規格の 7.5 を参照してください。言語リンケージは、コンパイラがパラメーターを処理する方法と、シンボルに名前マングリングを適用するかどうか (および場合によっては適用する方法) に影響します。

その特定のエラーに対するあなたの主張はさておき、コンパイラーはあなたのコードについて不平を言っています。これは、標準によれば無効であるためです。特に§14[temp]/4:

テンプレート名にはリンケージ (3.5) があります。非メンバー関数テンプレートは、内部リンケージを持つことができます。他のテンプレート名には、外部リンケージが必要です。内部リンケージを持つテンプレートから生成されたエンティティは、他の翻訳単位で生成されたすべてのエンティティとは異なります。テンプレート、テンプレートの明示的な特殊化 (14.7.3)、またはクラス テンプレートの部分的な特殊化には、C リンケージがあってはなりません。これらのいずれかのリンケージが C または C++ 以外のものである場合、動作は実装定義です。テンプレート定義は、1 つの定義規則 (3.2) に従うものとします。[注: 関数テンプレートおよびクラス テンプレートのメンバー関数のデフォルト引数は、テンプレートのインスタンス化 (14.5) を目的とした定義と見なされ、1 つの定義規則にも従わなければなりません。]

さまざまなコンパイラが標準にどのように準拠しているかを評価しようとする前に、時間をかけて標準を理解する必要があると本当に思います。質問があっても結構ですし、それに答えようと努力する人もいます。回答を読んで、その意味を理解しようとしたことを示すことは、敬意の表れです。ここでの前の回答の最後の段落のどの部分が不明ですか? あなたはそれを読みました?わかりましたか?そうでない場合、回答に対するコメントで質問しなかったのはなぜですか?

于 2010-08-07T21:32:05.733 に答える