[英]Define a static constexpr member of same type of a template class
[英]static constexpr member of same type as class being defined
我希望C類有一個類型為C的靜態constexpr成員。這在C ++ 11中是否可行?
嘗試1:
struct Foo {
constexpr Foo() {}
static constexpr Foo f = Foo();
};
constexpr Foo Foo::f;
g ++ 4.7.0說:'無效使用不完整類型'指的是Foo()
調用。
嘗試2:
struct Foo {
constexpr Foo() {}
static constexpr Foo f;
};
constexpr Foo Foo::f = Foo();
現在問題是在類定義中缺少constexpr
成員f
的初始化器。
嘗試3:
struct Foo {
constexpr Foo() {}
static const Foo f;
};
constexpr Foo Foo::f = Foo();
現在g ++抱怨在constexpr
重新聲明Foo::f
不同。
如果我正確地解釋標准,那是不可能的。
(§9.4.2/ 3)[...]可以使用constexpr說明符在類定義中聲明文字類型的靜態數據成員; 如果是這樣,它的聲明應指定一個大括號或等於初始化器,其中作為賦值表達式的每個initializer子句都是一個常量表達式。 [...]
從上面(以及靜態數據成員聲明中沒有關於非文字類型的單獨聲明的事實),我認為constexpr
的靜態數據成員必須是文字類型 (如§3.9/中所定義) 10),它一定有它包含在聲明中定義 。 使用以下代碼可以滿足后一種情況:
struct Foo {
constexpr Foo() {}
static constexpr Foo f {};
};
這與您的嘗試1類似,但沒有類外部定義。
但是,由於在聲明/定義靜態成員時Foo
不完整,編譯器無法檢查它是否是文字類型(如§3.9/ 10中所定義),因此它拒絕代碼。
請注意, 這篇后C ++ - 11文檔(N3308)討論了標准中當前constexpr
定義的各種問題,並提出修改建議。 具體而言,“建議的措辭”部分建議對§3.9/ 10進行修訂,這意味着將不完整類型作為一種文字類型。 如果要將該修訂納入標准的未來版本,您的問題將得到解決。
我認為GCC拒絕您的嘗試3是不正確的.C ++ 11標准(或其任何已接受的缺陷報告)中沒有規則表明如果事先聲明的話,變量的重新聲明必須是constexpr
。 最接近該規則的標准是[dcl.constexpr](7.1.5)/ 1_ :
如果函數或函數模板的任何聲明都有
constexpr
規范,則其所有聲明都應包含constexpr
規范。
Clang對constexpr
的實施接受了你的嘗試3。
理查德史密斯答案的更新,現在嘗試3編譯GCC 4.9和5.1,以及叮叮3.4。
struct Foo {
std::size_t v;
constexpr Foo() : v(){}
static const Foo f;
};
constexpr const Foo Foo::f = Foo();
std::array<int, Foo::f.v> a;
但是,當Foo是類模板時,clang 3.4失敗,但GCC 4.9和5.1仍然可以正常工作:
template < class T >
struct Foo {
T v;
constexpr Foo() : v(){}
static const Foo f;
};
template < class T >
constexpr const Foo<T> Foo<T>::f = Foo();
std::array<int, Foo<std::size_t>::f.v> a; // gcc ok, clang complains
Clang錯誤:
error: non-type template argument is not a constant expression
std::array<int, Foo<std::size_t>::f.v> a;
^~~~~~~~~~~~~~~~~~~~~
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.