mạnh gõ enums:
C++ 11 giới thiệu mạnh mẽ gõ enum
s, sử dụng enum class
:
#include <iostream>
enum class Color
{
Green = 0
};
enum class Fruit
{
Banana = 0
};
int main() {
Color c = Color::Green;
switch (c)
{
case Fruit::Banana:
std::cerr << "Banana" << std::endl;
break;
}
return 0;
}
Mã này sẽ thất bại chính xác như bạn hy vọng:
test.cc:18:17: error: could not convert '(Fruit)0' from 'Fruit' to 'Color'
Lưu ý: enum class
không gây Green
và Banana
được trong không gian tên kèm theo nữa, vì vậy bạn phải viết một cách rõ ràng Color::
và Fruit::
bây giờ, nhưng bạn làm cũng được typesafety.
Những vấn đề cảnh báo trong C++ 03
Tôi không nghĩ rằng cảnh báo về vấn đề này trong C++ 03 sẽ làm cho nhiều ý nghĩa, nó sẽ trở thành cơ bản chỉ là tiếng ồn.
Mọi người sử dụng enum
s làm hằng số thời gian biên dịch khá thường xuyên, ngay cả đối với những thứ như trường bit. Để cảnh báo có ý nghĩa, bạn phải nắm bắt những thứ như enum { foo=0xf }; int c = foo;
và nhiều mã cổ phiếu được phân tán với các chuyển đổi int
/enum
. (Cho phép điều này sẽ đánh bại điểm của bất kỳ kiểm tra loại mạnh hơn).
Tệ hơn nữa mặc dù sẽ được enum
s được sử dụng trong hầu hết các loại bối cảnh lập trình meta, nơi vô danh enum
s không chỉ được sử dụng một cách tự do thay thế cho nhau với int
loại một cách thường xuyên:
template <int I>
struct is_odd {
enum { value = !(I % 2) };
};
template <int I>
struct foo {
static void bar() { /* I is true */ }
};
template <>
struct foo<0> {
static void bar() { /* I is false */ }
};
int main() {
foo<is_odd<201>::value>::bar();
int i = is_odd<200>::value;
}
nhưng chúng cũng sử dụng đệ quy như lưu trữ địa phương:
template <int N>
struct factorial {
enum {
// This enum is *not* compatible with the one in N-1
value = N * factorial<N - 1>::value
};
};
template <>
struct factorial<0> {
enum { value = 1 };
};
Đó là một phần lý do tại sao enum class
đã được yêu cầu để giới thiệu một cách không bẻ addin g loại an toàn trên trạng thái hiện tại của enum
s trong C++. Sẽ có rất nhiều cảnh báo từ mã hiện tại rằng một cảnh báo sẽ là vô dụng vì những thứ như thế này.
Ngay cả trong ví dụ câu lệnh switch khá đơn giản, bạn cho thấy, một cái gì đó như thế này là hợp pháp:
#include <iostream>
enum Color { Green = 0x1, Red = 0x2 };
enum Fruit { Banana = 0x3 };
int main() {
int v = Green|Red;
Color c = Color(v);
switch (c) {
case Banana:
std::cerr << "Banana" << std::endl;
break;
}
return 0;
}
Mặc dù đây là quy phạm pháp luật ở đây nó không vô cùng có ý nghĩa, nhưng những thứ như được sử dụng khá thường xuyên và có ý nghĩa trong " bit-twiddling "C mã vẫn còn. Điểm của ví dụ này là bằng cách cho phép một số int
< ->enum
chuyển đổi ở bất kỳ đâu nó có nghĩa là nghiêm ngặt về loại enum
sau này sẽ được hiển thị vô nghĩa. Trong trường hợp chung, bạn không thể phát hiện xem loại chuyển đổi này có xảy ra hay không (nó có thể có trong một đơn vị dịch thuật khác).
enum class
là cách tốt nhất để giới thiệu độ chặt chẽ như vậy một cách rõ ràng mà không ảnh hưởng xấu đến mã hiện có.
Trình biên dịch nào? – FailedDev
Không có yêu cầu chẩn đoán cho nó trong 6.4.2 của C++ 11, nếu đó là những gì bạn có nghĩa là "nên trình biên dịch đưa ra một cảnh báo?". Vì vậy, câu trả lời cho câu hỏi bạn hỏi là "không", nhưng có lẽ câu hỏi bạn muốn hỏi là "có bất kỳ trình biên dịch nào trong đó tôi có thể bật cảnh báo như vậy không, và nếu như vậy thì sao?" ;-) –
Ồ, và "các nhãn được quảng cáo để int" - nó không phải là khá đơn giản. Các nhãn được chuyển thành kiểu được quảng bá 'c', ít nhất là' int' và 'int' là đủ cho enum mà bạn đã xác định, nhưng nó có thể là một kiểu khác, như' unsigned int' hoặc 'long long '. –