2006/07/18

C++ Initializer

昨天看到一行怪異程式碼:

char change[27] = {"abcdefghijklmnopqrstuvwxyz"};

直覺是不會過,但可得的編譯器全給過。於是翻閱 Holy Standard,最後在 Clause 8.5, par.13, p.146 找到:

If T is a scalar type, then a declaration of the form

T x = { a };

is equivalent to

T x = a;

其中 "scalar type" 的定義在 Clause 3.9, par.10, p.53:

Arithmetic types (3.9.1), enumeration types, pointer types, and pointer to member types (3.9.2), and cv-qualified versions of these types (3.9.3) are collectively called scalar types. Scalar types, POD-struct types, POD-union types (clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called POD types.

因此 array 並非 scalar types。不過邏輯上,標準書說的是「若『T 為 scalar type』,則『T x = { a }; 等價於 T x = a;』」,p => q 無法推得 ~p => ~q,因此效果上是保證 T 為 scalar type 時所發生的事,對於其它非 scalar type 的 T,編譯器有權決定是否要實作那個等價關係。例如以下這句:

vector<int> v = {vector<int>()};

g++ 3.4.2 不給過,但 g++ 4.1.0 給過,應該是版本演進而放寬限制(又不違背標準)。至於 Tchar[] 的情形(也就是一開始的問題),所有編譯器一致放行,或許是巧合,也可能是實作上較為方便,目前只能猜測。

另外,查閱標準途中,在 Clause 8.5, par.8, p.148 看到

An initializer for an aggregate member that is an empty class shall have the form of an empty initializer-list {}. [Example:

struct S { };
struct A {
S s;
int i;
} a = { { } , 3 };

—end example] An empty initializer-list can be used to initialize any aggregate. If the aggregate is not an empty class, then each member of the aggregate shall be initialized with a value of the form T() (5.2.3), where T represents the type of the uninitialized member.

之後又花了不少時間,為了區分 zero-initialization、default-initialization、value-initialization,在標準書內展開兩萬五千里長征,晚一點補上。

--
律師真痛苦 XD。