2015-11-05 49 views
6

我想寫一個CRTP來包含派生類型的static constexpr,因爲這對於一個類是不可能的。此代碼在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 :: a',而不是像'Derived :: constants :: 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尚未將a視爲constexpr,因爲它未能急於實例化其定義。查看錯誤#24541

+0

但是你不能這樣做'static_assert(Derived :: ax == 1,「」)'',這種類型會破壞'constexpr'的目的。 – user975989

+0

@ user975989這似乎是一個叮噹蟲。 – Columbo

+0

@ user975989找到DR並將其添加到答案中。 (有趣的是,使用的例子是非常重要的!) – Columbo

相關問題