2015-11-05 11 views
6

派生型のstatic constexprを含むCRTPを作成しようとしています。これは、1つのクラスでは実現できないためです。このコードはGCCでうまくコンパイルされますが、clangはDerivedが不完全な型であると不平を言っています。どちらが正しいですか?クラス定義を基本クラスに渡すと、クラス定義は完了していますか?

template<class T> 
class Base { 
public: 
    static constexpr T a = T(1), b = T(20); 
}; 

class Derived : public Base<Derived> { 
public: 
    int x; 
    constexpr Derived(int x) : x(x) {} 
}; 
+1

Derivedのコンストラクタでローカル変数xとメンバの名前が同じであることに注意してください – Brahim

+0

基本クラス内で派生オブジェクトを静的に保つことはベストアイデアではないことを指摘したいと思います。 –

+0

唯一の理由この方法は、 'Derived '型の' static constexpr'を 'Derived'に入れることができないためです。私はこれをやりたいと思っていました: 'Derived :: constants :: a'のようなものではなく、' Derived :: a'です。 – user975989

答えて

2

Derived右定義時に起こるBase<Derived>がインスタンス化される時点([class.mem]/2)、で不完全です。 constexprを使用し、[class.static.data]/3のようにイニシャライザを必要とし、Base<Derived>がインスタンス化されると、イニシャライザを含む静的データメンバー([temp.inst]/3)の宣言も同様になります。しかし、イニシャライザは不完全な型のオブジェクトを作成しようとしていますが、これは不正な形です。

あなたが代わりにconstとしてあなたのメンバを宣言することができます。

template<class T> 
class Base { 
public: 
    static const T a; 
}; 
template <typename T> 
constexpr T Base<T>::a = T(1); 

初期化子が定義で今があるため、この初期化子のインスタンス化は、例えばまで延期することができますDerivedが完了しました。 DemoとClang。

Clangはまだaconstexprとして処理していないことに注意してください。バグ#24541を参照してください。

+0

しかし、 'constexpr'の目的を敗北させる' static_assert(Derived :: ax == 1、 "") 'はできません。 – user975989

+0

@ user975989これはClangバグのようです。 – Columbo

+0

@ user975989 DRを見つけて回答に追加しました。 (面白いことに、使用されている例は多くのポイントです!) – Columbo