次の変数からのリンケージについていくつか質問があります。C++03の7.1.1/7の例とコンパイラー(Comeau、Clang、GCC)の実験により、次の種類のリンケージにたどり着きました。
最初
static
に、次にextern
static int a; // (a) extern int a; // (b) valid, 'a' still internal
セクション3.5によると、私には明らかです。(a)内部リンクを意味します。また、(b)は、名前「a」が静的であると宣言されているため((a)によって)、内部リンケージも意味します。
最初
extern
に、次にstatic
extern int b; // (c) static int b; // (d) invalid!
まず、(c)は外部リンケージを意味します。ただし、(d)は、名前「b」が(d)によって静的であると宣言されているため、内部リンクを意味します。暗黙のリンケージが一貫していないため、7.1.1/7によるとこれは無効です。
最初
const
に、次にextern
const double pi1 = 3.14; // (e) extern const double pi1; // (f) valid and 'pi1' is internal
まず、(e)は内部リンケージを意味します。これは、constであり、明示的な外部リンケージを宣言しておらず、以前は外部リンケージを暗示していなかったためです。また、(f)externリンケージを意味し、エラーになるはずです。これは、externという名前を明示的に宣言しているためですが、コンパイラーはそれを内部に保持します。なぜそうなのか? それが私の質問です。
最初
extern
に、次にconst
extern const double pi2; // (g) const double pi2 = 3.14; // (h) valid and 'pi2' is external
ここで、(g)は、externを明示的に宣言したため、外部リンケージを意味します。また、(h)は、(g)externを明示的に宣言しているため、外部リンケージも意味します。
次のテンプレートを使用して、3と4のリンケージを実験的に見つけました(2番目の引数は外部リンケージが必要です)
template<typename T, T&> struct ensure { };
ensure<const double, pi1> e1; // failed
ensure<const double, pi2> e2; // succeeded
要約:チャールズベイリーとの話し合いは非常に実り多いものであることが判明し3.5/3
、重要な箇条書きが
名前空間スコープ(3.3.5)を持つ名前は、
- constとして明示的に宣言されており、externとして明示的に宣言されておらず、外部リンケージを持つように以前に宣言されていないオブジェクトまたは参照。
ポイントを見ると(f)
、以下に示すように、2つの解釈は異なる結論に達します。
宣言されているが、
pi1
宣言されている最初の解釈ノート。したがって、変数には外部リンケージがあります。const
extern
2番目の解釈は、「宣言された」の両方の出現を解釈して、同じ宣言を参照します。このように、それは宣言されているが、では
const
ないextern const
ことを意味します。(e)
は宣言されており、宣言されconst
ていないことに注意してください。extern const
したがって、pi1
内部リンクを提供します。
さて、どのような解釈が正しいのでしょうか?その言葉遣いからは判断できませんが、コンパイラーはこれを2番目の方法で解釈しているようです。特に、最初の解釈を行う場合、名前が宣言され、以前に外部リンケージを使用して明示的に宣言3.5/3
されていない有効なシナリオがないため、の最後に引用された部分は不要になります。const
extern