34

次のコードがあります。

class MyClass
{
  static constexpr bool foo() { return true; }
  void bar() noexcept(foo()) { }    
};

sincefoo()static constexpr関数であり、bar宣言される前に定義されているため、これは完全に受け入れられると思います。

ただし、g++次のエラーが表示されます。

 error: ‘static constexpr bool MyClass::foo()’ called in a constant expression

定数式で関数を呼び出す機能がの要点であるconstexprため、これは役に立ちません。

clang++はもう少し役に立ちます。noexceptへの引数は定数式でなければならないというエラー メッセージに加えて、次のように表示されます。

note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
                      ^

それで...これは2パスコンパイルの問題ですか?コンパイラーがクラス内のすべてのメンバー関数を定義する前に宣言しようとしているという問題はありますか? (クラスのコンテキストの外では、どちらのコンパイラもエラーをスローしないことに注意してください。) これには驚きました。static constexpr直感的には、クラスの内外を問わず、すべての定数式でメンバー関数を使用できない理由がわかりません。

4

1 に答える 1

19

TC がコメント内のいくつかのリンクで示したように、標準はこれについて明確ではありません。を使用した末尾の戻り値の型でも同様の問題が発生しdecltype(memberfunction())ます。

中心的な問題は、クラス メンバーが宣言されているクラスが完成するまで、クラス メンバーが宣言されているとは一般に見なされないことです。fooしたがって、が でありstatic constexpr、その宣言が の宣言よりも前にあるという事実に関係なく、が完了barするまで定数式で使用できると見なすことはできません。MyClass

Shafik Yaghmourが指摘したように、クラス内のメンバーの順序への依存を回避するための標準内の試みがあり、元の質問の例をコンパイルできるようにすると、順序の依存関係が導入されることは明らかです (foo宣言する必要があるため)前bar)。ただし、関数は内で呼び出すことはできませんが、式自体はクラス内の以前の宣言に依存する可能性があるため、順序付けにはすでにわずかな依存関係があります。constexprnoexceptnoexcept

class MyClass
{
    // void bar() noexcept(noexcept(foo())); // ERROR if declared here
    static constexpr bool foo();
    void bar() noexcept(noexcept(foo())); // NO ERROR
}

(これは実際には 3.3.7 の違反ではないことに注意してください。ここで可能な正しいプログラムはまだ1 つしかないためです。)

この動作は、実際には標準に違反している可能性があります。TC は (以下のコメントで)fooここは実際にはクラス全体のスコープで参照する必要があると指摘しています。g++ 4.9.2 と clang++ 3.5.1 はどちらも、 が最初に宣言されたときにエラーで失敗しますが、barが最初に宣言されたときにはエラーや警告なしでコンパイルされますfooEDIT: clang ++トランクリビジョン238946(3.7.0のリリース直前から)が最初に宣言されたときに失敗しません。barg++ 5.1 はまだ失敗します。

興味深いことに、次のバリエーションは、 g++ ではなく、clang++ で「異なる例外指定子」を引き起こします。

class MyClass
{
  static constexpr bool foo2();
  void bar2() noexcept(noexcept(foo2()));
};

constexpr bool MyClass::foo2() { return true; }
void MyClass::bar2() noexcept(noexcept(MyClass::foo2())) { }

エラーによると、の宣言noexcept仕様はに評価され、これは の不一致と見なされます。bar2noexcept(false)noexcept(noexcept(MyClasss::foo2()))

于 2015-04-15T23:09:35.830 に答える