18

C ++の静的クラスのメンバーは、標準の言い回しのために少し混乱を引き起こしました。

9.4.2静的データメンバー [class.static.data]

クラス定義での静的データメンバーの宣言は定義ではありません...

ただし、constexprは、その宣言(たとえば、クラス定義)で初期化する必要があります(AFAIK、標準からの引用符を見つけることができませんでした)。

constexprの制限のため、静的constexpr配列にアクセスしようとするまで、クラスの外部で静的メンバーを定義するための必要条件を実際に忘れていました。この関連する質問は、配列メンバーを定義する正しい方法を提供しますが、クラステンプレートでのこの定義への影響について興味があります。

これは私が最終的に得たものです:

template<typename T>
class MyClass
{
private:
  static constexpr std::size_t _lut[256] = { /* ... */ };
  T _data;

public:
  static constexpr std::size_t GetValue(std::size_t n) noexcept
  {
    return _lut[n & 255];
  }

  // ...
};

template<typename T>
constexpr std::size_t MyClass<T>::_lut[256];

これは正しい構文ですか?特に定義でのテンプレートの使用は厄介に感じますが、GCCはすべてを適切にリンクしているようです。

フォローアップの質問として、非配列の静的constexprメンバーを同様に定義する必要がありますか(クラス外のテンプレート定義を使用)?

4

2 に答える 2

15

それが誰かを助ける場合に備えて、constexprを使用したGCC4.7で次のことがうまくいきました。

template<class T> class X {
  constexpr static int s = 0;
};
template<class T> constexpr int X<T>::s; // link error if this line is omitted

私はこれが「適切」であるかどうかについては何も主張していません。私はそれをより資格のある人に任せます。

于 2014-03-14T19:26:59.617 に答える
14

私はあなたが9.4.2p3が欲しいと思います:

不揮発性const staticデータメンバーが整数型または列挙型の場合、クラス定義での宣言で、代入式であるすべての初期化子句が定数式である中括弧または等しい初期化子を指定できます(5.19)。リテラル型の静的データメンバーは、指定子を使用してクラス定義で宣言できます。その場合、その宣言は、代入式であるすべての初期化子句が定数式である中括弧または等しい初期化子を指定するものとします。[...]メンバーがプログラムでodr-used(3.2)であり、名前空間スコープ定義に名前空間スコープが含まれていない場合でも、メンバーは名前空間スコープで定義されます。constexpr初期化子

テンプレート静的データメンバーの定義は、テンプレート宣言(14p1)です。14.5.1.3p1の例は次のとおりです。

template<class T> class X {
  static T s;
};
template<class T> T X<T>::s = 0;

ただし、上記のように、クラス内宣言で初期化子が指定されているconstexpr staticorメンバーは、名前空間スコープ定義に初期化子を含めるべきではないため、構文は次のようになりますconst static

template<class T> class X {
  const static T s = 0;
};
template<class T> T X<T>::s;

非配列(つまり、整数または列挙)静的constexprデータメンバーとの違いは、左辺値から右辺値への変換での使用がodr-useではないことです。そのアドレスを取得するか、それへのconst参照を形成する場合にのみ、それを定義する必要があります。

于 2013-01-18T09:47:40.370 に答える