問題描述
我目前正在編寫 C++ 內存編輯庫,對于讀/寫 API,我使用類型特征(std::is_pod、std::is_same)和 boost::enable_if 來提供 3 個重載:
- POD 類型.例如MyMem.Read(SomeAddress);
- 字符串類型.例如MyMem.Read>(SomeAddress);(這實際上不是讀出 C++ 字符串,而是讀出 C 樣式字符串并將其轉換為 C++ 字符串.)
- 矢量類型.例如MyMem.Read>(SomeAddress, NumElem);(這實際上并不是讀出向量,而是讀出 C 風格的數組并將其轉換為向量.)
重載 2 和 3 只是重載 1 的包裝器".(因此,如果您正在讀取 std::vector 或 std::basic_string 并且 T 不是 POD,它將失敗,因為它應該.)
最近我想使用 std::array 進行一堆讀取和寫入,因為我知道在編譯時我想要讀取和寫入的數據的大小(我正在編寫一個關于 PE 文件格式的包裝器).
我編寫了使用 std::array 的代碼,然后打算添加另一個用于檢測和處理 std::array 類型的重載,但我不小心點擊了編譯,令我驚訝的是它起作用了!
我目前正在使用 MSVC 10,結果證明對于 std::array,如果 T 是 POD,則 std::array 是 POD.(這意味著我可以只使用重載 1 并且它可以工作.)
我的問題是,這是由 C++ 標準保證還是由實現決定.
我知道我可以自己檢查標準,但我并不像我信任本網站上的一些語言律師那樣信任自己,所以我認為最好獲得第二意見".;)
謝謝
附言此處提供的代碼(它是僅標頭庫):http://code.google.com/p/hadesmem/source/browse/trunk/HadesMem-v2/Hades-Memory/Hades-Memory/MemoryMgr.h#86
§23.3.1:
<塊引用>數組是一個集合(8.5.1),可以用語法array a
其中 initializer-list 是一個逗號分隔的列表,最多包含 N 個元素,其類型可轉換為 T.
在 C++03 中,POD 是根據聚合定義的:一個類,其中每個子對象都是原生的,或者聚合是 POD.因此,通過向后兼容性,C++0x std::array
是 POD.
或者,作為肛門,可以將 §9/5(定義平凡類)9/6(定義標準布局)和 9/9(將前面的要求組合到 POD)的要點與 8.5 的要點進行比較.1/1,定義聚合.
8.5.1:
<塊引用>聚合是一個數組或類(第 9 條),沒有用戶提供的構造函數(12.1),沒有用于非靜態數據成員的大括號或等號初始化器(9.2),沒有私有或受保護的非靜態數據成員(第 11 條),沒有基類(第 10 條),也沒有虛函數(10.3).
Clause 9 的要求確實涵蓋了array
,只要它的元素類型也是 POD 并且實現沒有聲明 operator=
或 move
> 里面 array
除了規范.
要真正肛門,17.5.2.2 說
<塊引用>- 為了說明起見,第 18 條到第 30 條和附錄 D 沒有描述復制/移動構造函數、賦值運算符或(非虛擬)析構函數,其語義與默認生成的語義相同(12.1,12.4、12.8).
- 未指定實現是否為此類成員函數簽名或默認生成的虛擬析構函數提供了顯式定義.
模板類數組
的偽代碼注釋是
//沒有顯式構造/復制/銷毀聚合類型
construct/copy/destroy
是否包括 operator=
(賦值)或 move
?它可能應該,但我認為,根據最嚴格的解讀,它確實如此.
請注意,這不僅會影響"POD 性,還會影響"約翰內斯提到的微不足道的可復制性.
I'm currently writing a C++ memory editing library and for the read/write APIs I use type traits (std::is_pod, std::is_same) and boost::enable_if to provide 3 overloads:
- POD types. e.g. MyMem.Read(SomeAddress);
- String types. e.g. MyMem.Read>(SomeAddress); (This doesn't actually read out a C++ string, it reads out a C-style string and converts it to a C++ string.)
- Vector types. e.g. MyMem.Read>(SomeAddress, NumElem); (This doesn't actually read out a vector, rather it reads out a C-style array and converts it to a vector.)
Overloads 2 and 3 are simply 'wrappers' around overload 1. (So if you're reading a std::vector or std::basic_string and T is not POD it will fail, as it should.)
Recently I wanted to use std::array for a bunch of reads and writes because I knew the size of the data I wanted to read and write at compile time (I was writing a wrapper around the PE file format).
I wrote the code to use std::array, and then intended to add another overload for detection and handling of std::array types, but I accidentally hit compile and to my surprise it worked!
I'm currently using MSVC 10 and it turns out that for std::array if T is POD then std::array is POD. (Which means I can just use overload 1 and it works.)
My question is whether this is guaranteed by the C++ standard or left up to the implementation.
I know I could check the standard myself, but I don't trust myself as much as I trust some of the language lawyers on this site, so I figured it would be best to get a 'second opinion'. ;)
Thanks
P.S. Code available here (it's a header-only lib): http://code.google.com/p/hadesmem/source/browse/trunk/HadesMem-v2/Hades-Memory/Hades-Memory/MemoryMgr.h#86
§23.3.1:
An array is an aggregate (8.5.1) that can be initialized with the syntax
array a<T, N> = { initializer-list };
where initializer-list is a comma separated list of up to N elements whose types are convertible to T.
In C++03, POD was defined in terms of aggregate: a class where every subobject is native or an aggregate is POD. So, by backwards compatibility, a C++0x std::array
is POD.
Or, to be anal, one can compare the bullet-points of §9/5 (defining trivial class) 9/6 (defining standard-layout) and 9/9 (combining preceding requirements into POD) with those of 8.5.1/1, which defines aggregates.
8.5.1:
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal- initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
Indeed the requirements in Clause 9 cover array
as long as its element type is also POD and the implementation does not declare operator=
or move
inside array
in addition to the specifications.
To be really anal, 17.5.2.2 says
- For the sake of exposition, Clauses 18 through 30 and Annex D do not describe copy/move constructors, assignment operators, or (non-virtual) destructors with the same apparent semantics as those that can be generated by default (12.1, 12.4, 12.8).
- It is unspecified whether the implementation provides explicit definitions for such member function signa- tures, or for virtual destructors that can be generated by default.
The note in the pseudo-code for template class array
is
// No explicit construct/copy/destroy for aggregate type
Does construct/copy/destroy
include operator=
(assignment) or move
? It probably should, but I don't think, by the strictest reading, it does.
Note that this "affects" not only POD-ness, but also trivial copyability as Johannes mentions.
這篇關于是 std::array<T, S>如果 T 是 POD 就保證是 POD?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!