2017-10-05 7 views
2

私はここにCRTPテンプレートクラスがあります。打ち鳴らすには:constexprの変数を持つことができない非リテラルタイプ

template <typename S> 
class Base 
{ 
    public: 
    constexpr static S NOT_SET{0}; 
}; 

struct Derived : public Base<Derived> 
{ 
}; 

クラン(5.0.0)がこれを受け入れない:

5 : <source>:5:24: error: constexpr variable cannot have non-literal type 'const Derived' 
    constexpr static S NOT_SET{0}; 
        ^
8 : <source>:8:25: note: in instantiation of template class 'Base<Derived>' requested here 
struct Derived : public Base<Derived> 
         ^
5 : <source>:5:24: note: incomplete type 'const Derived' is not a literal type 
    constexpr static S NOT_SET{0}; 
        ^
8 : <source>:8:8: note: definition of 'Derived' is not complete until the closing '}' 
struct Derived : public Base<Derived> 
    ^
1 error generated. 
Compiler exited with result code 1 

しかし、 gcc(4.9.2と6.2でテスト済み)はうまくいきます。

clangでこれを行うにはどうすればいいですか?

答えて

2

Derivedは、クラステンプレートBaseで使用しようとすると完全な型ではないため、実際には使用できません。そのタイプの変数を宣言できるようにするには、そのタイプが完全でなければならないからです。それを回避する方法はありません。
要約すると、タイプは}の終了時に完了します(その他の例外は、メンバー関数内のようにケースには関係ありません)。
これは、標準の(working draft)を言うことである:

クラスは、クラス指定の閉鎖}で完全に定義されたオブジェクトのタイプ(または完全なタイプ)であると考えられます。
classメンバ指定内では、クラスは、関数本体、デフォルト引数、noexcept指定子、およびデフォルトのメンバ初期化子(ネストされたクラスのものを含む)内の完全とみなされます。
それ以外の場合は、それ自身のクラスメンバー指定内では不完全とみなされます。

したがって、clangは正しく、エラーは多かれ少なかれ同じです。


コメントに記載されているとおり、回避する方法があります。派生型がconstexprのコンストラクタブルである限り、そのを返さない基本クラスのconstexpr関数を定義することができます(バージョンを意味します)。

+0

ありがとう:しかし、GCCのこの「機能」を利用している既存のコードベースを移植したい場合、あなたのアドバイスは何ですか? – Anton

+1

派生した型がconstexprで構成可能である限り、(それが何であれ)_not set_バージョンを返す基本クラスにconstexpr関数を定義できます。それはあなたのために働くことができますか? – skypjack

+0

はい、いい考えです。ありがとうございました。私はあなたの答えを受け入れるだろうが、あなたは後世のために答えにあなたのコメントを入れることができると思いますか? :-) – Anton

関連する問題