6

Here's a minimal example:

#include <iostream>

struct B {
  B() { x = 42; }
  static int x;
};  

int B::x;

template <int N>
struct A {
  int foo() { return b.x; }
  static B b;
};

template<int N>
B A<N>::b;

//template struct A<2>; // explicit instantiation with N = 2 (!)

int main(int argc, char **argv) {
  std::cout << A<1>().foo() << std::endl;
  return 0;
}

This program writes 42 using g++ 4.9.2, but writes 0 using Visual Studio 2015 RC. Also, if I uncomment the explicit instantiation, VS2015RC also gives 42, which is quite interesting, as the template parameter here is different from the one used in the main function.

Is this a bug? I assume that g++ is correct, as there is a reference to b inside foo, so B's constructor should be called.


EDIT: There is a simple workaround - if there is a non-static variable in B, that is referenced in A, VS2015RC will compile correctly:

// ...

struct B {
  B() { x = 42; }
  static int x;
  int y;                         // <- non-static variable
};

// ...

template <int N>
struct A {
  int foo() { b.y; return b.x; } // <- reference to b.y
  static B b;
};

This seems to work, even though b.y, as a statement, is obviously NOP.

4

2 に答える 2

6

[basic.start.init] から:

静的保存期間 (3.7.1) またはスレッド保存期間 (3.7.2) を持つ変数は、他の初期化が行われる前にゼロで初期化されます (8.5)。オブジェクト o の定数初期化子は、オブジェクトが非リテラル クラス型であっても、o とそのサブオブジェクトの constexpr コンストラクターを呼び出すことを除いて、定数式である式です。[ ... ]

ゼロ初期化と定数初期化をまとめて静的初期化と呼びます。他のすべての初期化は動的初期化です。静的初期化は、動的初期化が行われる前に実行されます。

この場合、bは静的に初期化されますが、b.x動的に初期化されます (コンストラクターは constexpr ではありません)。しかし、次のものもあります。

メインの最初のステートメントの前に、静的記憶域期間を持つ非ローカル変数の動的初期化が行われるかどうかは、実装によって定義されます。初期化が main の最初のステートメントの後のある時点まで延期される場合、初期化される変数と同じ変換単位で定義された関数または変数の最初の odr-use (3.2) の前に発生するものとします。

[basic.def.odr] からの Odr 使用手段:

名前が潜在的に評価される式 ex として表示される変数 x は、左辺値から右辺値への変換 (4.1) を x に適用して、重要な関数を呼び出さない定数式 (5.20) を生成しない限り、ex によって ODR 使用されます。 [ ... ]

しかし、評価b.xしても定数式は得られないので、そこでやめることができます - b.xis odr-used byA<N>::foo()で、これは最初のodr-useでもあります。したがって、初期化は の前に行う必要はありませんが、前main()に行う必要がありますfoo()。したがって、0 を取得した場合、それはコンパイラ エラーです。

于 2015-07-13T13:05:18.333 に答える