其實這是一個文不對題的問題。正文中的問題,和標題中引用的東西無關。

C++98 §9.2/4

A member-declarator can contain a constant-initializer only if it declares a static member of const integral or
const enumeration type

歌詞大意:常整型、常枚舉型的靜態成員才能就地初始化。

所以題目正文中的「字元串數組不是字面值常量類型」並不準確。原因是 tokenName 的類型是 char const *[6],連常量都不夠格,更別提常整型、常枚舉型了。

C++98 沒法就地初始化,解決方法是寫成傳統的(假設題目中是筆誤,這裡讓 tokenName 變成了常量):

class ListLexer
{
public:
static char const *const tokenName[];
};

char const *const ListLexer::tokenName[6] = {"na","&","NAME","COMMA","LBRACK","RBRACK"};

C++11 中放寬了條件,就地初始化額外為 constexpr 敞開了大門,於是改成 constexpr 你就可以寫:

class ListLexer
{
public:
static constexpr char const *tokenName[] = {"na","&","NAME","COMMA","LBRACK","RBRACK"};
};

C++14 還沒定稿,所以就不管了……

剛好遇到了這個問題

#include &

struct A {
static constexpr int scxv = 0;
static const int scv = 0;
};

constexpr int A::scxv; // 必須顯示定義,否則下面無法push_back
const int A::scv; // 必須

int main() {
std::vector& vec;
vec.push_back(A::scxv); // 必須顯示類外定義
vec.push_back(A::scv); // 必須顯示類外定義
}

這個算是坑嗎?以後標準會不會取消這樣的限制。


這句話本質上還是 odr-used 的問題。好像很多初學者不知道這個概念,垃圾 msvc 也是要負一部分責任的。

如果類內的 static const 成員初始化但是沒有定義,它只能被很有限地使用。類似於 C 語言中的一個 define 操作似的,可能都沒有自己的內存空間,作為一個常量是沒啥問題的。但是當這個成員被 odr-used 時,那就必須需要一個類外的定義。最典型的情況是 vector 的push_back操作,需要這個成員的引用,這時就必須需要一個定義。

當然,標準沒有規定 odr-used 卻找不到定義時具體會怎麼樣。不同編譯器有不同的實現,一般就是報一個鏈接錯誤。然而垃圾 msvc 則是隱式地為所有 static const 成員定義。所以很多 msvc 用戶根本體會不到 odr-used 的存在。

至於題主的問題,和這句話是兩回事,有人回答了,我就不贅述了。


主要和static的語義有關係,static不屬於任何一個類對象實例獨有,也就是不包含this指針訪問,也不額外佔用類對象的空間。

所以做直觀的做法就是在類「外部」定義,也就是申請空間。


大家說的是什麼東西?類內聲明不是定義這個是規定的結果不是原因。

簡單說就是類聲明被多個文件包含時怎麼鏈接的問題,static 成員需要外部鏈接,看成定義就重複定義了,當然現在有了 inline。


在c++ primer第五版中只涉及了C++11的特性,所以應該是不支持static const int N_A=0這種語法的...

以下的回答假設你這段話出自《C++primer》第五版。

這段話中的常量靜態數據成員是指同時加了constexpr和static關鍵字的數據成員。由於其加了constexpr所以可以在類內定義初始值(一般情況下靜態成員變數是不可以在類內定義初始值的),是constexpr的特性決定了可以在類內定義初始值,因為constexpr約束了其一定為常量表達式,可能在編譯時期就將constexpr的變數全部替換成了對應的字面值

因此constexpr和static關鍵字修飾的數據成員實際上在實際運行中是不存在的,而是以值的方式替換了。我覺得可能是為了方便,也許C++只在相應的作用域內進行替換,因此只在類內進行替換。所以導致在類外加了constexpr和static關鍵字的變數實際上是不存在的,所以如果需要在類的外部使用該常量靜態數據成員,則也需要在類的外部進行定義。

下劃線部分帶有個人猜測,謹慎接收,不過用來理解這段話應該還可以。
推薦閱讀:
相关文章