web-dev-qa-db-ja.com

イニシャライザなしのconstexpr静的データメンバー

#include <complex>

struct S
{
  static std::complex<double> constexpr c;
};

イニシャライザがないため、gccはエラーを生成します。 ClangとMSVCはエラーを生成しません。

私の知る限り、constexpr静的データメンバーは、引数なしで呼び出すことができるコンストラクターを持つクラスタイプであっても(この場合のように)、初期化子を持っている必要があります。残念ながら、私は自分の仮定を裏付ける最新のC++標準を持っていません。

したがって、正しいコードはコンストラクターで初期化する必要があります。たとえば、次のようになります。

struct S
{
  static std::complex<double> constexpr c {};
};

どのコンパイラが正しいか、どれが間違っているかを誰かが証明できますか?

15
x y

GCCは間違っています。

GCCは、constexpr変数にC++ 14ルールを使用します。これには、初期化子を指定する必要があります。これは P0386 ごとに変更されます(太字のテキストは新しく追加されたテキストです):

9.2.3.2p3で、変更:

不揮発性n on-inlineconst静的データメンバーが整数型または列挙型である場合、クラス定義での宣言でabを指定できますrace-or-equal-initializerここで、すべての(= /// =)initializer-clause割り当て式は定数式(5.20)です。 リテラル型の静的データメンバーは、constexpr指定子を使用してクラス定義で宣言できます。その場合、その宣言は、代入式であるすべての初期化子句が定数式である中括弧または等しい初期化子を指定するものとします。 [注:どちらの場合も、メンバーは定数式で表示される場合があります。 —エンドノート] メンバーがプログラムでodr-used(3.2)であり、名前空間スコープ定義にイニシャライザーが含まれていない場合でも、メンバーは名前空間スコープで定義されます。インライン静的データメンバークラス定義で定義でき、b race-or-equal-initializerを指定できます。メンバーがconstexpr指定子で宣言されている場合、名前空間で再宣言できます。初期化子のないスコープ(この使用法は非推奨です。DXを参照してください)。他の静的データメンバーの宣言では、b race-or-equal-initializerを指定してはなりません。

7
xskxzr

この特定のケースには、2つの答えがあります。

  • C++ 14の場合、gccはrightです(つまり、constexpr静的データメンバーには初期化子が必要です)。
  • C++ 17以降の場合、gccはwrongです。これは、準拠コードのコンパイルを拒否するためです。

以前のケース:ドラフト中 N3797 (C++14)、9.4.2.3(静的データメンバー)[class.static.data](強調鉱山):

リテラル型staticデータメンバーは、constexpr指定子を使用してクラス定義で宣言できます。もしそうなら、その宣言はbrace-or-equal-initializerを指定するものとします。initializer-clauseつまりAssignment-expressionは定数式です。

参照: http://en.cppreference.com/w/cpp/language/static#Constant_static_members

「この場合特定のの場合」と言ったのは、std::complexdoubleに特化しています これはLiteralTypeです。したがって、上記のルールが適用されます。一般的な(つまり、非リテラル)タイプについては、 codekaizers answer を参照してください。

後者の場合:C++の場合17xskxzrの答え を参照してください。

4
andreee

から dcl.constexpr#1

static指定子で宣言された関数またはconstexprデータメンバーは、暗黙的にinline関数または変数です。

constexprstaticデータメンバーは暗黙的にinlineです。

また、 class#static.data-emphasismineから:

inlinestaticデータメンバーはclass定義で定義でき、mayは_brace-or-equal-initializer_。


したがって、GCCは間違っています。 _brace-or-equal-initializer_はnot厳密に必要です

参照: N4659 C++ 17ドラフト

1
Joseph D.