6

次のコードスニペットは、g++およびclang++で正常に機能します。

// bsp1.cc
class A {
public:
  A(int, char const *);

  int value;
  const char * name;
};

class B {
public:
  static const A many_as[];
};

A const B::many_as[] 
{ { 0, "zero" }, 
    { 1, "one" }, 
    { 2, "two" }, 
    { 3, "three" }, 
    { 77, 0 } };

テンプレート化するクラスBを変更すると、次のようになります。

// bsp2.cc
class A {
public:
  A(int, char const *);

  int value;
  const char * name;
};

template<typename T>
class B {
public:
  static const A many_as[];
};

template<>
A const B< int >::many_as[] 
{ { 0, "zero" }, 
  { 1, "one" }, 
  { 2, "two" }, 
  { 3, "three" }, 
  { 77, 0 } };

clang++は次の場合に失敗します。

tmp/bsp2.cc:19:1: error: expected ';' after top level declarator
{ { 0, "zero" }, 
^
1 error generated.

g++はまだこれに満足しています。

バージョン情報:g ++(Debian 4.7.2-4)4.7.2、clangバージョン3.3(トランク171722)

として追加する=

A const B< int >::many_as[] =

また、clang++は幸せです。

私の質問:

  1. bsp2.ccは有効ですか?(言い換えれば、これはclang ++の問題ですか?)
  2. ?がある場合とない場合のbsp2の間に意味上の違いはあり=ますか?(つまり、バージョンを=「回避策」として使用できますか?)
  3. (ボーナス質問:)これが説明されているC ++ 11標準の段落を教えていただけますか?
4

1 に答える 1

6

9.4.2p2は、非テンプレート静的データメンバーの定義を指定します。含意によって、その構文は他の定義と同じであるため、中括弧または等しい初期化子の中括弧-初期化リストは絶対に問題ありません。テンプレート静的データメンバーの明示的な特殊化の定義は、14p1および14.5.1.3でカバーされており、暗黙的に、静的データメンバーの有効な定義は、テンプレート静的データメンバーの明示的な特殊化の定義に対して有効です。

実際、14.7.3p13は、デフォルトの初期化と定義を区別するために、テンプレート静的データメンバーの明示的な特殊化でbraced -init-listを使用することを明示的に示しています。

struct X {};
template<typename> struct Q { static X i; };
template<> X Q<int>::i{};

clangは標準の例からこの構文を受け入れることができないため、バグがclangにあることは明らかです。

この場合、回避策は絶対に有効です。を挿入することの意味論的含意(8.5p14)は=直接初期化(8.5p16)がコピー初期化(8.5p15)に変わることです。イニシャライザはbraced -init-list(8.5p17)であるため、list-initialization(8.5.4)が実行され、direct-list-initializationからcopy-list-initialization(8.5.4p1)に変更されますが、オブジェクト以降は配列であるため、アグリゲート(8.5.1p1)であり、アグリゲートの初期化が実行されます。これは、直接/コピー初期化の区別がわかりません。

にコンストラクターが存在すると、それが集約になるのを防ぐことに注意してくださいA。これは、コンストラクターが実行時に呼び出される可能性が高いことを意味します。コンストラクターを削除すると、の配列はA再帰的な集計になり、コンパイル時に完全に初期化できます(データはオブジェクトファイルに直接配置されます)。

于 2013-01-14T13:41:26.357 に答える