2013-02-20 28 views
33

Có thể xác định cardinality của một C++ enum class:Có thể xác định số phần tử của lớp C++ enum không?

enum class Example { A, B, C, D, E }; 

Tôi cố gắng để sử dụng sizeof, tuy nhiên, nó sẽ trả về kích thước của một phần tử enum.

sizeof(Example); // Returns 4 (on my architecture) 

Có cách nào tiêu chuẩn để nhận được cardinality (5 trong ví dụ của tôi) không?

+0

Tôi nghĩ có thể có một cơ chế C++ 11 cụ thể – bquenin

+4

Đây không phải là bản sao, nhân tiện. 'enum' và' enum class'es là những khái niệm rất khác nhau. – Shoe

+0

@ Shoe ... là họ thực sự, mặc dù? –

Trả lời

43

Không trực tiếp, nhưng bạn có thể sử dụng các thủ thuật sau đây:

enum class Example { A, B, C, D, E, Count }; 

Sau đó cardinality có sẵn như là (int)Example::Count.

Tất nhiên, điều này chỉ hoạt động tốt nếu bạn để giá trị của enum được gán tự động, bắt đầu từ 0. Nếu đó không phải là trường hợp, bạn có thể gán một cách thủ công duy trì một hằng số riêng biệt anyway:

enum class Example { A = 1, B = 2, C = 4, D = 8, E = 16, Count = 5 }; 

một bất lợi là trình biên dịch sẽ cho phép bạn sử dụng Example::Count như một tham số cho một giá trị enum - vì vậy hãy cẩn thận nếu bạn sử dụng này! (Cá nhân tôi thấy đây không phải là một vấn đề trong thực tế.)

+5

Mặc dù điều này sẽ vi phạm nếu bất kỳ giá trị nào được đặt thành một cái gì đó khác với giá trị mặc định. Vì vậy, sử dụng cẩn thận. – juanchopanza

+0

Ok cảm ơn cho các tip – bquenin

+1

Các giá trị enum là loại an toàn trong một lớp enum vì vậy 'Đếm' sẽ được loại Ví dụ ở đây và không int, phải không? Bạn sẽ phải đúc 'Đếm' thành một int đầu tiên để sử dụng nó cho kích thước. –

1

Không, bạn phải viết mã trong mã.

3

Một thủ thuật bạn có thể thử là thêm một giá trị enum vào cuối danh sách của bạn và sử dụng nó làm kích thước. Trong ví dụ của bạn

enum class Example { A, B, C, D, E, ExampleCount }; 
5
enum class TEST 
{ 
    BEGIN = __LINE__ 
    , ONE 
    , TWO 
    , NUMBER = __LINE__ - BEGIN - 1 
}; 

auto const TEST_SIZE = TEST::NUMBER; 
+0

Thông minh! Không thể có bất kỳ bình luận hoặc khoảng cách bất thường, tất nhiên, và đối với các tệp nguồn thực sự lớn, kiểu giá trị cơ bản có thể lớn hơn nó sẽ khác. –

+0

@Kyle Strand: có vấn đề đó: sử dụng char và bạn cũng có hơn 256 điều tra viên. Nhưng trình biên dịch có cách cư xử tốt để thông báo cho bạn về việc cắt bớt, v.v. __LINE__ là một số nguyên theo nghĩa đen và sử dụng #line có giới hạn [1, 2147483647] – UglyCoder

+0

Ah, được rồi. Tuy nhiên, ngay cả một enum mà nếu không sẽ là một 'short' có thể được bumped lên' int' e.g. khi xây dựng sự thống nhất. (Tôi muốn nói đây là một vấn đề với sự hợp nhất xây dựng hơn là với thủ thuật được đề xuất của bạn, mặc dù.) –

6
constexpr auto TEST_START_LINE = __LINE__; 
enum class TEST { // Subtract extra lines from TEST_SIZE if an entry takes more than one 
    ONE = 7 
    , TWO = 6 
    , THREE = 9 
}; 
constexpr auto TEST_SIZE = __LINE__ - TEST_START_LINE - 3; 

này có nguồn gốc từ UglyCoder's answer nhưng cải thiện nó theo ba cách.

  • Không có yếu tố phụ trong enum type_safe (BEGINSIZE) (Cameron's answer cũng có vấn đề này.)
    • Trình biên dịch sẽ không phàn nàn về họ bị mất tích từ một câu lệnh switch (một vấn đề quan trọng)
    • Chúng không thể được chuyển vô tình đến các hàm mong đợi enum của bạn. (không phải vấn đề thường gặp)
  • Nó không yêu cầu đúc để sử dụng. (Cameron's answer cũng gặp sự cố này.)
  • Phép trừ không gây rối với kích thước của loại lớp enum.

Nó giữ lại UglyCoder's lợi thế hơn Cameron's answer mà điều tra viên có thể được gán giá trị tùy ý.

Một vấn đề (được chia sẻ với UglyCoder nhưng không phải với Cameron) là nó làm cho dòng mới và nhận xét đáng kể ... điều bất ngờ. Vì vậy, ai đó có thể thêm mục nhập có khoảng trắng hoặc nhận xét mà không cần điều chỉnh tính toán của TEST_SIZE.

1

Bạn cũng có thể xem xét static_cast<int>(Example::E) + 1 để loại bỏ yếu tố phụ.

+2

Câu trả lời này là đúng cho vấn đề lập trình cụ thể này, nhưng nói chung là xa thanh lịch và dễ bị lỗi. Enum có thể được mở rộng với các giá trị mới trong tương lai có thể thay thế 'Example :: E' thành giá trị cuối cùng trong enum. Ngay cả khi điều này không đúng, giá trị chữ 'Example :: E' có thể thay đổi. – Matthias

2

Có một mẹo dựa trên X() - macro: hình ảnh, bạn có enum sau:

enum MyEnum {BOX, RECT}; 

Định dạng lại nó để:

#define MyEnumDef \ 
    X(BOX), \ 
    X(RECT) 

Sau đó, đoạn mã sau định nghĩa kiểu enum:

enum MyEnum 
{ 
#define X(val) val 
    MyEnumDef 
#undef X 
}; 

Và mã sau tính toán số lượng thành phần enum:

template <typename ... T> void null(T...) {} 

template <typename ... T> 
constexpr size_t countLength(T ... args) 
{ 
    null(args...); //kill warnings 
    return sizeof...(args); 
} 

constexpr size_t enumLength() 
{ 
#define XValue(val) #val 
    return countLength(MyEnumDef); 
#undef XValue 
} 

... 
std::array<int, enumLength()> some_arr; //enumLength() is compile-time 
std::cout << enumLength() << std::endl; //result is: 2 
... 
Các vấn đề liên quan