16

現在のプログラムは clang によって拒否されましたが、gcc では正常にコンパイルされます。要約すると、次の単純化された例になります。

struct A {
  static constexpr inline int one();
};

inline constexpr int A::one() { return 1; }

int main() {
  return 0;
}

g++ 4.7.2 はエラーなしでコンパイルします ( g++ -std=c++11 -Wall -g -o main example.cpp)。clang++ 3.1 はそれを拒否します:

$ clang++ -std=c++11 -Wall -g -o main example.cpp 
example.cpp:6:25: error: conflicting types for 'one'
inline constexpr int A::one() { return 1; }
                        ^
example.cpp:3:31: note: previous declaration is here
  static constexpr inline int one();
                              ^
1 error generated.

私の賭けは、gcc が正しく、clang が間違っているということですか? プログラムは正当な C++11 である必要があります。

興味深い補足。が構造体内に実装されている場合one、clang はもう文句を言いません:

struct A {
  static constexpr inline int one() { return 1; }
}

gcc もこのバリアントを受け入れます。私の理解では、両方のバージョンは標準に従って同一である必要があります。それはclangのバグですか、それとも何か不足していますか?

4

3 に答える 3

10

これは Clang のバグです (Clang 3.2 で修正済み)。const問題は、関数の再宣言が以前の宣言と一致するかどうかを判断するときに、Clang が暗黙の影響を正しく処理していなかったことです。検討:

struct A {
  int f();                  // #1
  constexpr int f() const;  // #2 (const is implicit in C++11 and can be omitted)
  static constexpr int g(); // #3
};

int A::f() { return 1; }           // #4, matches #1
constexpr int A::f() { return 1; } // #5, matches #2, implicitly const
constexpr int A::g() { return 1; } // #6, matches #3, not implicitly const

のクラス外宣言 #5 を のメンバと照合する場合A、コンパイラには問題があります。コンパイラは、 の新しい宣言がどのような型をA::f持っているかをまだ認識していません。A::fが非静的メンバー関数である場合、その型はでint () constあり、静的メンバー関数である場合、その型はint ()(暗黙的ではないconst) です。

Clang 3.1 はこれを完全に正しく理解していませんでした。constexpr関数がメンバ関数である場合、constexpr暗黙的に作成されたものと想定していたためconst、#4 と #5 は機能しますが、#6 は機能しません。Clang 3.2 は、constexpr-implies-constルールを 2 回実装することでこれを修正します。1 回は再宣言マッチング (#5 は #2 を再宣言し、#1 ではなく再宣言すると見なされますが、まだ暗黙的ではありませんconst) で、もう 1 回前の宣言が選択されました (#5 に暗黙的な const を追加するため)。

于 2013-07-05T18:02:51.797 に答える
8

constexpr標準では、静的メンバー関数の定義をその宣言から分離できるかどうかについて明示的に言及していませんがconstexpr、7.1.5p1 の下で、コンストラクターの分離定義の次の例があります。

struct pixel {
  int x;
  int y;
  constexpr pixel(int); // OK: declaration
};
constexpr pixel::pixel(int a)
  : x(square(a)), y(square(a)) // OK: definition
  { }

constexprしたがって、関数が別個の宣言と定義を持つことができることは明らかです。また、7.1.5p1:

関数または関数テンプレートの宣言にconstexpr指定子がある場合、そのすべての宣言に指定子を含める必要がありconstexpr ます。

これは、constexpr関数が (複数の) 非定義宣言を持つことができることを意味します。

于 2012-12-17T11:11:40.960 に答える
2

g++ が正しいと確信しています。実際、これは g++のバグでした。定義とは別に static constexpr 宣言を行うことができると明示的に述べている標準の場所を見つけることができませんが、constexpr 指定子 (ここに要約されています) について説明しているセクション 7.1.5 を見ると、そうではありません。これは通常、許可されていることを意味します。

于 2012-12-17T04:54:03.863 に答える