定義が必要
あなたが提供したコードは非標準です。const static intメンバーの初期化子をクラスで直接提供できますが、それでも個別の定義を提供する必要があります。それは奇妙で、一種の予想外ですが、あなたはそれを次のように書くことが期待されています:
#include <algorithm>
struct Foo
{
static const int A = 1;
static const int B = 2;
};
const int Foo::A;
const int Foo::B;
int main()
{
return std::min(Foo::A, Foo::B);
}
標準からの引用は、C++のconstおよびstatic指定子の同様の質問にあります。
コードが定義なしで「機能する」ことがあるのはなぜですか?
定義を提供しなくても回避できることが多い理由については、定数式でのみこれらのメンバーを使用している場合、コンパイラーは常にそれらを直接解決し、リンカー解決のためのアクセスが残されません。これは、コンパイラが直接処理できない方法で使用した場合にのみ発生します。そのような場合にのみ、リンカはシンボルが未定義であることを検出します。これはおそらくVisualStudioコンパイラのバグだと思いますが、バグの性質を考えると、これまでに修正されるとは思えません。
ソースが「リンカー」カテゴリに分類される理由は私にはわかりません。それを理解するには、std::minを分析する必要があります。注:GCCを使用してオンラインで試したところ、機能しましたが、エラーは検出されませんでした。
代替:列挙型を使用
別の方法は、列挙型を使用することです。このバージョンは、static const int "inline"イニシャライザー(Visual Studio 6など)をサポートしていない古いコンパイラーを使用する場合にも役立ちます。ただし、std :: minを使用すると、列挙型で他の問題が発生し、明示的なインスタンス化またはキャストを使用するか、Nawazの回答のように1つの名前付き列挙型にAとBの両方を含める必要があることに注意してください。
struct Foo
{
enum {A = 1};
enum {B = 2};
};
int main()
{
return std::min<int>(Foo::A, Foo::B);
}
基準
注:Stroustrup C ++ FAQでさえこれを誤解し、標準のように厳密に定義する必要はありません。
クラス外の定義がある場合にのみ、静的メンバーのアドレスを取得できます。
この定義は、9.4.2の標準で要求されています。
C ++ 03の文言:
メンバーがプログラムで使用され、名前空間スコープ定義に初期化子が含まれていない場合でも、メンバーは名前空間スコープで定義されます。
9.4.2のC++11の表現は少し異なります。
3メンバーがプログラムでodr-used(3.2)である場合、メンバーは引き続き名前空間スコープで定義されます。
3.2は、odr-useについて次のように述べています。
3名前が潜在的に評価される式exとして表示される変数xは、xが定数式(5.19)に表示されるための要件を満たすオブジェクトであり、exが式の潜在的な結果のセットの要素である場合を除き、odrで使用されます。 e、ここで、左辺値から右辺値への変換(4.1)がeに適用されるか、eが破棄された値の式です(5節)。
4すべてのプログラムには、そのプログラムでodrで使用されるすべての非インライン関数または変数の定義が1つだけ含まれている必要があります。診断は必要ありません。
私はodrの使用規則を理解していないため、C++11の文言の正確な意味がわからないことを認めなければなりません。