Quy tắc chung ở đây là bạn không thể sử dụng khởi tạo thành viên trong lớp của biến thành viên nếu đó là static
(và cũng không phải const int
), tuy nhiên có một số ngoại lệ (không có trường hợp nào áp dụng cho trường hợp của bạn).
Trong tiêu chuẩn C++ 98, bạn có thể chỉ thành viên khởi static const int
Trong tiêu chuẩn 11 C++, bạn có thể khởi tạo thành viên tất cả mọi thứ trừ static
(với ngoại lệ đối với các tiêu chuẩn C++ 98).
Bạn có thể làm được việc này nếu thành viên tĩnh của bạn là constexpr
:
§ 9.4.2 (tháng 11 năm 2014 dự thảo)
If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression (5.20). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.
Để giải thích đoạn này một chút rõ ràng hơn: Nếu bạn muốn cố gắng thu hút mọi thứ với constexpr
, loại của bạn phải là "theo nghĩa đen".
Một loại đen (§ 3.9.10):
- Có một "tầm thường" destructor
- Có chỉ nhà xây dựng biểu thức hằng
- Có chỉ lớp đen kiểu cơ sở dữ liệu và các thành viên
- Hoặc là một aggregate type
- Hoặc là
void
, vô hướng (ví dụ: int
), tham chiếu hoặc mảng loại chữ
Một destructor là "tầm thường" nếu:
- Đó là trình biên dịch tạo ra (ví dụ: bạn không xác định một)
- Và mỗi đối tượng thành viên không tĩnh có một destructor tầm thường
Với tất cả những điều này, bạn có thể có một cái nhìn tại mã của bạn và nghĩ rằng "Hm, tôi cũng có thể làm cho tất cả các nhà thầu của tôi constexpr
và sau đó thay đổi static const CColorf blue
thành static constexpr CColorf blue
và tôi rất tốt. "
Tuy nhiên, lớp học của bạn "chưa hoàn thành" tại thời điểm bạn khai báo tĩnh.Hãy suy nghĩ về những điều sau đây example:
class A{
private:
A member;
}
Mỗi thể hiện của A
hiện nay có một thể hiện của A
. Trình biên dịch phân bổ bao nhiêu byte cho A
? Nó không thể nói được. Vô cùng nhiều, có lẽ, do đệ quy. A là không đầy đủ bên trong lớp riêng của nó. Bạn có vấn đề tương tự về sự không hoàn thiện. Tuy nhiên, chúng ta hãy làm cho nó một con trỏ thay vì:
class A{
private:
A* member;
}
Bây giờ thật dễ dàng vì A*
là một loại con trỏ, mà trình biên dịch biết kích thước của.
Vì vậy, bây giờ bạn nghĩ "Được rồi, tôi sẽ chỉ làm cho static constexpr CColorf blue
một con trỏ như static constexpr CColorf* blue = new CColorf(0.0f, 0.0f, 1.0f);
Nhưng bạn có thể không, bởi vì các nhà điều hành new
không phải là constexpr
.
Và bạn không thể thử const
bởi vì chúng tôi đã đi qua tại sao.
vì vậy, có lẽ bạn nghĩ về quá tải toán tử new
là constexpr
, nhưng you can't do that either.
Vì vậy, bạn đã hết may mắn.
Khai nó 'constexpr'. 'CColof' là một kiểu chữ, do đó nó sẽ hoạt động. – Columbo
@Columbo: không phải 'constexpr' phải được sử dụng với các biểu thức (hoặc hàm), chứ không phải khai báo? –
... không biết ý bạn là gì, nhưng bạn có vẻ bối rối. 'constexpr' là một trình khai báo khai báo (khai báo khai báo) và do đó chỉ có thể được sử dụng trong các khai báo. – Columbo