constexprを同じクラス内のテンプレートパラメータとして使用する際のエラー

次のC ++ 0xコードをコンパイルしようとすると、エラーが発生します。

template struct foo { };

struct bar {
    static constexpr int number() { return 256; }

    void function(foo &);
};

gcc 4.6.1では、エラーメッセージは次のようになります。

test.cc:6:27: error: ‘static constexpr int bar::number()’ used before its definition
test.cc:6:28: note: in template argument for type ‘int’

clang 2.8では、エラーメッセージは次のようになります。

test.cc:6:20: error: non-type template argument of type 'int' is not an integral
      constant expression
        void function(foo &);
                          ^~~~~~~~
1 error generated.

constexpr 関数を基本クラスに移動すると、gccで動作し、clangで同じエラーメッセージが表示されます。

template struct foo { };

struct base {
    static constexpr int number() { return 256; }
};

struct bar : base {
    void function(foo &);
};

コードが間違っていますか、gcc 4.6のC ++ 0x実装の制限またはバグですか?コードが間違っている場合、それはなぜ間違っていますか、C ++ 11標準のどの節が間違っていると言いますか?

6
うーん..私は先ほどこれについて議論したと思います。インライン関数定義は、クラス定義の直後に 定義されているかのように扱われます。クラス定義の内部ではまだ利用できません。代わりに static const int number = 256; または static constexpr int number = 256; と言うことができます。
追加された 著者 Kerrek SB,
@CesarB:いいえ、必ずしもそうではありません。アドレスを取得しようとしない限り、実際には静的定数の実装を提供する必要はありません。
追加された 著者 Kerrek SB,
@ケレスクSBああ、私はそれを知らなかった。それを答えとして書くべきです。
追加された 著者 Seth Carnegie,
@KerrekSB:AFAIK、 static const int number = 256; を使用する場合、無駄な4バイトを無駄に追加する const int bar :: number; .data インライン関数を使用すると、それを防ぐことができます。しかし、それが static constexpr int number = 256; の場合にも当てはまりません。
追加された 著者 CesarB,
@KerrekSB:このC ++ 0xドラフトを見て、私は[class.static.data]に次のように書いています: "odr-used [...]"の場合、メンバーはまだ名前空間のスコープで定義されます。 at [basic.def.odr]: "[...]名前が潜在的に評価される式として現れる変数は、定数式に現れるための要件を満たしているオブジェクトでなければodr-usedであり、定数式ではlvalue-to - 値の変換はすぐに適用されます。[...] " expr.constと[conv.lval]が何を言っているかによって、あなたが正しいかのように見えます。さらに、この方法でMSVCのために #ifndef は必要ありません!
追加された 著者 CesarB,

2 答え

C ++では、クラスのメンバー関数のインライン定義は、クラス内のすべての宣言が解析された後にのみ解析されます。したがって、最初の例では、 function()が宣言された時点で、コンパイラは number()の定義を認識できません。

(clangのリリース版はconstexpr関数の評価をサポートしていないので、あなたのテストケースはそこで動作しません)。

5
追加された

私は、次のコードでは、simillarエラーがあります:

struct Test{
     struct Sub{constexpr Sub(int i){}};
    static constexpr Sub s=0;
};

"エラー: 'constexpr Test :: Sub :: Sub(int)'がgcc 4.7.1で定数式で呼び出されました。 whileこれは正常にコンパイルされます:

struct Sub{constexpr Sub(int i){}};
struct Test{
    static constexpr Sub s=0;
};
1
追加された
あなたが貢献しているものが、ユーザーが提示している質問にする場合にのみ、回答を提供してください。あなたが投稿したものは、より多くのコメントとみなされます。これは、サイトをより多く使用する際に投稿する特権を取得します。 S.O.に参加してくれてありがとう。歓迎します。
追加された 著者 David,