このようなものは、コンパイルされた場合、C++ の 1 つの定義規則に明らかに違反します。
// Case 1
// something.h
struct S {};
struct A
{
static const S val = S();
};
something.h が複数のモジュールに含まれている場合、の定義A::val
が繰り返されるためです。ただし、これは許可されています。
// Case 2
// someOtherThing.h
struct B
{
static const int val = 3;
};
私が理解しているように、このケースが問題ない理由B::val
は、 が整数型のコンパイル時の定数であるためです。そのため、コンパイラは本質的にすべての参照をB::val
リテラルで検索して置換できます3
(逆アセンブリを調べると、これが示されます)。まさにそれが行うことです)。したがって、最終製品にはある意味ゼロの定義があるB::val
ため、ODR は適用されません。ただし、次の点を考慮してください。
// Case 3
// yetAnotherThing.h
struct C
{
static const int val = 3;
const int* F()
{
return &val;
}
};
これは許可されており、この場合、一部のメモリ位置が の値を格納するために実際に確保されていることが逆アセンブリによって示されますC::val
。表面的には、これは、yetAnotherThing.h が複数のモジュールに含まれている場合、static const int val = 3
ストレージが「放出」されるため、ODR に違反するようになったことを意味します。それでも、コンパイラもリンカ (VC++2012) も文句を言いません。
なんで?これは、コンパイラ/リンカーの作成者が対処しなければならない不快な特殊なケースですか? もしそうなら、同じシステムを使用してケース 1 を機能させられないのはなぜですか?
(標準からの関連する引用は歓迎されますが、必ずしも質問に答えるとは限りません。標準で、pink_elephants
キーワードの使用によって数値 42 のすべてのインスタンスが 666 に置き換えられるべきであると述べられている場合、それはそれになりますが、私たちはなぜそのような奇妙なルールが存在するのか、まだ疑問に思っています。)