8

メンバーstaticのクラス内初期化に少し混乱しています。constたとえば、以下のコードでは:

#include <iostream>

struct Foo
{
    const static int n = 42;
};

// const int Foo::n; // No ODR

void f(const int& param)
{
    std::cout << param << std::endl;
}

int g(const int& param)
{
    return param;
}

template<int N>
void h()
{
    std::cout << N << std::endl;
}

int main()
{
    // f(Foo::n); // linker error, both g++/clang++
    std::cout << g(Foo::n) << std::endl; // OK in g++ only with -O(1,2 or 3) flag, why?!
    h<Foo::n>(); // this should be fine
}

Live example

定義しませんFoo::n(行はコメント化されています)。f(Foo::n)したがって、リンク時に呼び出しが失敗することを期待していますが、実際にそうです。ただし、次の行std::cout << g(Foo::n) << std::endl;は、.gcc などの最適化フラグを使用するたびに、gcc によってのみ正常にコンパイルおよびリンクされます (clang は依然としてリンカー エラーを出力します) -O1/2/3

  1. 最適化がオンになっている場合、gcc (gcc5.2.0 および gcc 4.9.3 で試行) がコードをコンパイルおよびリンクするのはなぜですか?
  2. そして、クラス内の static const メンバーの唯一の使用法は、呼び出しのようなテンプレート パラメーターなどの定数式であると言うのは正しいh<Foo::n>ですか?その場合、コードはリンクする必要がありますか?
4

4 に答える 4

6

コンパイラーは、最適化中に次のアクションを実行すると思います。

  • const static int nはどこでもインライン化されます。変数にメモリが割り当てられていないため、変数nへの参照が無効になります。プログラムがコンパイルされないように、関数f()には参照が必要です。n

  • 機能gは短くシンプルです。効果的にインライン化され、最適化されています。最適化後、関数gは への参照を必要とせずn、定数値 42 を返すだけです。

解決策は、クラス外で変数を定義することです。

struct Foo
{
    const static int n;
};

const int Foo::n = 42;
于 2015-09-27T21:05:23.507 に答える
4

正式には、ODR 違反は未定義の動作であるため、コンパイラは任意の動作を示す可能性があります。そのため、最適化レベルとコンパイラによって動作が変化します。コンパイラには、特定の動作を維持する義務はありません。

于 2015-09-27T21:33:51.427 に答える