2009-05-12 31 views
27

Tôi đã cố gắng đọc một chút tiêu chuẩn C++ để tìm ra cách làm việc của enum. Thực sự có nhiều hơn tôi nghĩ ban đầu.Loại nằm dưới của một C++ enum trong C++ 0x

Đối với một kiểu liệt kê phạm vi, rõ ràng là loại cơ bản là int trừ khi được quy định khác với mệnh đề enum-base (nó có thể là bất kỳ loại tích phân nào).

enum class color { red, green, blue}; // these are int 

Đối với các liệt kê chưa được kiểm tra, có vẻ như loại cơ bản có thể là loại tích phân sẽ hoạt động và không lớn hơn int, trừ khi cần.

enum color { red, green, blue}; // underlying type may vary 

Vì loại cơ bản của enumarations chưa được điều chỉnh không được chuẩn hóa, cách tốt nhất để xử lý trường hợp tuần tự hóa là gì? Cho đến nay, tôi đã chuyển đổi thành int khi viết sau đó tuần tự hóa thành một số int và đặt biến số enum của mình trong một chuyển đổi khi đọc, nhưng có vẻ hơi phức tạp. Có cách nào tốt hơn?

enum color { red, green, blue }; 
color c = red; 
// to serialize 
archive << (int)c; 
// to deserialize 
int i; 
archive >> i; 
switch(i) { 
    case 0: c = red; break; 
    case 1: c = green; break; 
    case 2: c = blue; break; 
} 
+2

enum lớp chỉ là C++ 0x ... – Klaim

+2

+1, không chắc chắn lý do tại sao câu hỏi này đã được -1ed ... –

+1

Có thể vì người hỏi dường như không thể phân biệt giữa một hiện có và một tài liệu tiêu chuẩn đề xuất? –

Trả lời

5

Tôi chưa đọc bất kỳ nội dung nào của C++ 0x nên tôi không thể nhận xét về điều đó.

Đối với serializing, bạn không cần chuyển đổi khi đọc enum trở lại - chỉ cần cast nó vào loại enum.

Tuy nhiên, tôi không truyền khi ghi vào luồng. Điều này là bởi vì tôi thường thích viết một toán tử < < cho enum để tôi có thể bắt các giá trị xấu được viết, hoặc sau đó tôi có thể quyết định viết ra một chuỗi thay thế.

enum color { red, green, blue }; 
color c = red; 

// to serialize 
archive << c; // Removed cast 

// to deserialize 
int i; 
archive >> i; 
c = (color)i; // Removed switch 
+1

Cảm ơn ý tưởng viết một toán tử << cho enum. Tôi nên tự nghĩ về điều đó. – criddell

+0

Trong nhận xét của bạn, bạn đã đề cập đến viết một toán tử << và tôi hiểu rằng mã của bạn ở trên sẽ hoạt động chính xác với quá tải tại chỗ. Tuy nhiên, nếu << không bị quá tải, người ta nên cast c thành int trước khi serialize, đúng không? – criddell

+0

Không, tôi sẽ không chuyển sang int vì nếu bạn đã làm điều đó và sau đó thêm toán tử enum << sau đó, bạn phải tìm tất cả các vị trí trong mã viết enum và loại bỏ các diễn viên. – markh44

16

enum lớp là một tính năng C++0x, nó không được trình bày trong C++ 03.

Trong tiêu chuẩn C++, liệt kê không an toàn kiểu. Chúng là các số nguyên hiệu quả, ngay cả khi các kiểu liệt kê là khác biệt. Điều này cho phép so sánh giữa hai giá trị enum của các kiểu liệt kê khác nhau. Sự an toàn duy nhất mà C++ 03 cung cấp là một số nguyên hoặc một giá trị của một kiểu enum không chuyển đổi hoàn toàn sang kiểu enum khác. Ngoài ra, loại tích phân cơ bản, kích thước của số nguyên, không thể xác định rõ ràng; nó được thực hiện. Cuối cùng, các giá trị liệt kê được phạm vi đến phạm vi kèm theo. Do đó, không thể có hai bảng liệt kê riêng biệt để có các tên thành viên phù hợp. C++ 0x sẽ cho phép phân loại đặc biệt liệt kê không có vấn đề nào trong số này. Này được thể hiện bằng cách sử dụng khai báo lớp enum

Ví dụ (từ bài viết wikipedia):

enum Enum1;     //Illegal in C++ and C++0x; no size is explicitly specified. 
enum Enum2 : unsigned int; //Legal in C++0x. 
enum class Enum3;    //Legal in C++0x, because enum class declarations have a default type of "int". 
enum class Enum4: unsigned int; //Legal C++0x. 
enum Enum2 : unsigned short; //Illegal in C++0x, because Enum2 was previously declared with a different type. 

Đối với phần serialization (mà tôi nghĩ là không nằm trong câu hỏi ban đầu), tôi thích tạo một lớp trợ giúp dịch các mục enum thành chuỗi tương đương (và ngược lại), vì các tên thường ổn định hơn các giá trị số nguyên mà chúng đại diện, vì các mục enum có thể (và đôi khi) được sắp xếp lại mà không thay đổi hành vi mã.

1

enum class color: Đây có phải là C++/CLI (C++ .NET) hoặc mã C++ 0x trong tương lai không?

Để tuần tự hóa, bạn có thể nhận được kích thước của enum với sizeof(color) để biết số byte cần sao chép.

14

Tôi quyết định tạo câu trả lời mới vì cũ của tôi quá lộn xộn. Dù sao chỉ muốn nói điều gì đó về C++ 11, nơi bạn có thể lấy kiểu liệt kê cơ bản bằng cách sử dụng kiểu này:

std::underlying_type_t<E> 

Và vì lợi ích, ý tưởng phân giải quá tải. Nhưng xin vui lòng sử dụng tên để lưu trữ các điều tra, theo đề xuất của @ lothar.

Độ phân giải quá tải bắt nguồn từ thực tế là có tồn tại một khuyến mãi từ một điều tra đến lần đầu tiên int, unsigned int, dài, unsigned long có thể đại diện cho tất cả các giá trị của loại cơ bản của nó. Một chuyển đổi cho bất kỳ loại số nguyên nào khác được xếp hạng thấp hơn và độ phân giải quá tải sẽ không thích nó.

char (& f(int))[1]; 
char (& f(unsigned int))[2]; 

char (& f(long))[3]; 
char (& f(unsigned long))[4]; 

char const* names[] = { 
    "int", "unsigned int", 
    "long", "unsigned long" 
}; 

enum a { A = INT_MIN }; 
enum b { B = UINT_MAX }; 
enum c { C = LONG_MIN }; 
enum d { D = ULONG_MAX }; 

template<typename T> void print_underlying() { 
    std::cout << names[sizeof(f(T()))-1] << std::endl; 
} 

int main() { 
    print_underlying<a>(); 
    print_underlying<b>(); 
    print_underlying<c>(); 
    print_underlying<d>(); 
} 

Và nó in cái này ở đây:

int 
unsigned int 
int 
unsigned int 

Nó không phải quan tâm đặc biệt đến vấn đề serialization này (vì kích thước của dữ liệu tuần tự không phải là chiều rộng không đổi, và điều này có thể gây ra vấn đề khi điều tra và kiểu cơ bản của nó được thay đổi), nhưng nói chung là thú vị để tìm ra một kiểu lưu trữ toàn bộ một kiểu liệt kê. Chúc mừng!

+0

'std :: basics_type' là giải pháp tốt nhất để nhận đúng loại. Chỉ cần chỉnh sửa nhỏ: Trình trợ giúp ** 'std :: bases_type_t ' ** có sẵn thông qua ** C++ 14 **; cho ** C++ 11 ** bạn phải sử dụng ** 'std :: bases_type :: type' ** thay thế. – ollo

5
#include <type_traits> 

enum a { bla1, bla2 }; 
typedef typename std::underlying_type<a>::type underlying_type; 

if (std::is_same<underlying_type, int>::value) 
    std::cout << "It's an int!" << endl; 
else if (std::is_same<underlying_type, unsigned int>::value) 
    std::cout << "It's an uint!" << endl; 
+2

Đó là phong tục để thực sự sử dụng văn bản để giải thích những gì một cái gì đó đang làm, thay vì chỉ làm một khối mã. –

+0

Tôi sẽ đâm một lời giải thích. Mã này đang sử dụng một chút ma thuật mẫu để có được trình biên dịch tìm ra loại cơ bản của enum. Tôi đã hỏi làm thế nào để tìm ra loại cơ bản cho mục đích serialization và bit này của mã sẽ làm điều đó. – criddell