レ
名前のない名前空間内の名前に対して明示的な外部リンケージを行うことが役立つのはどのような場合ですか?
外部リンケージの必要性は、C++03 テンプレートにとって重要でした。たとえば、テンプレート引数としての関数ポインタは、外部リンケージの関数へのポインタでなければなりませんでした。たとえば、次のコードは C++03 コンパイラではコンパイルできません。
template< void(*f)() >
void tfunc() { f(); }
#include <stdio.h>
static void g() { printf( "Hello!\n" ); }
int main()
{
tfunc<g>();
}
C++11 コンパイラで問題なくコンパイルできます。
そのため、C++11 では、外部リンケージを持ちながら翻訳単位間で名前が競合しない匿名名前空間メカニズムは、技術的にクラスにのみ必要です。クラスには外部リンケージがあります。他の翻訳単位では発生しないことが保証されているクラス名を選択する必要はありません。
C++11 では、テンプレート パラメーターだけでなく、匿名名前空間内のものに外部リンケージがあるかどうかのルールも変更されました。C++03 では、匿名名前空間自体が匿名名前空間 (C++03 §3.5/4 最後のダッシュ + C++03 §7.3.1.1/1) 内にない限り、匿名名前空間は正式に外部リンケージを持っていました。C++11 では、無名名前空間に正式な内部リンケージがあります。
名前空間のリンクがないため、これはリンカには関係ありませんが、物事のリンクを記述するための正式なデバイスとして重要です。
C++11 §3.5/4:
名前のない名前空間、または名前のない名前空間内で直接的または間接的に宣言された名前空間には、内部リンケージがあります。他のすべての名前空間には外部リンケージがあります。上記の内部リンケージが与えられていない名前空間スコープを持つ名前は、それが
変数の名前である場合、囲んでいる名前空間と同じリンケージを持ちます。または
— 関数; または
— 名前付きクラス (条項 9)、またはクラスがリンケージ目的で名前をtypedef
持つ宣言で定義された名前なしクラス (7.1.3)。typedef
または
— 名前付き列挙 (7.2)、またはtypedef
列挙がリンケージ目的で typedef 名を持つ宣言で定義された名前のない列挙 (7.1.3)。または
— リンケージを持つ列挙に属する列挙子。また
— テンプレート。
他の質問に進む前に、標準からのこの引用に注意する価値があります。
名前のない名前空間のエンティティは外部リンケージを持っている可能性がありますが、それらは翻訳単位に固有の名前によって効果的に修飾されているため、他の翻訳単位からは決して見ることができません。
宣言されている名前空間に関係なく、エンティティは他の翻訳単位から見えるため、明らかに間違っています。extern "C"
幸いなことに、メモは非規範的です。つまり、メモは言語を定義しません。
レ
名前のない名前空間内の名前に対して明示的に外部リンクを作成する方法
const
非変数または関数を として宣言するだけextern
です。const
非変数または関数を as として
宣言しextern "C"
、リンケージを extern にすることができますが、同時に、リンクに関する限り名前空間を無関係にすることができます。C 言語には名前空間がありません。
namespace {
extern "C" void foo() {} // Extern linkage
} // namespace <anon>
void bar() {} // Also extern linkage, but visible to other TUs.
レ
」 リンクが実際に外部であることを確認する方法
リンケージは、C++11 では §3.2 である「 ODR 」と略されることが多い One Definition Rule との競合の可能性などに影響します。
したがって、リンケージの動作を確認する 1 つの方法は、上記のソースから生成された 2 つのオブジェクト ファイルをリンクすることです。これは、同じソース コードを持つ 2 つの翻訳単位があるかのようにします。
C:\my\forums\so\088> g++ -c anon.cpp -o xo & g++ -c anon.cpp -o yo
C:\my\forums\so\088> g++ main.cpp xo yo
yo:anon.cpp:(.text+0x0): `foo' の複数定義
xo:anon.cpp:(.text+0x0): 最初にここで定義
yo:anon.cpp:(.text+0x7): 複数の「bar()」定義
xo:anon.cpp:(.text+0x7): 最初にここで定義
collect2.exe: エラー: ld が 1 つの終了ステータスを返しました
C:\my\forums\so\088> _
リンカは、 の複数の定義について不平を言いますfoo
。これは、C 言語バインディングと同様に、リンカに関する限り、inline
グローバル名前空間の非外部リンケージ メンバとして 2 つの (競合する可能性がある) 定義があるように見えるためです。