Câu hỏi (Làm thế nào) tôi có thể đếm các mục trong một enum?


Câu hỏi này đến với tâm trí của tôi, khi tôi có một cái gì đó như

enum Folders {FA, FB, FC};

và muốn tạo một mảng các vùng chứa cho mỗi thư mục:

ContainerClass*m_containers[3];
....
m_containers[FA] = ...; // etc.

(Sử dụng bản đồ nó sẽ thanh lịch hơn nhiều để sử dụng: std::map<Folders, ContainerClass*> m_containers;)

Nhưng để quay trở lại câu hỏi ban đầu của tôi: Nếu tôi không muốn mã hóa cứng kích thước mảng, có cách nào để tìm ra có bao nhiêu mục trong Thư mục không? (Không phụ thuộc vào ví dụ: FC là mục cuối cùng trong danh sách cho phép những thứ như ContainerClass*m_containers[FC+1] nếu tôi không nhầm.)


76
2018-01-20 15:37


gốc


Bài đăng này có thể trả lời câu hỏi của bạn: stackoverflow.com/questions/1390703/enumerate-over-an-enum-in-c  . - StackedCrooked
Câu hỏi là một chút underspecified. Theo tiêu chuẩn C ++, int(FA) | int(FB) | int (FC) cũng là một giá trị pháp lý cho Folders biến. Nếu bạn đang định cỡ m_containers để bất kỳ Folders biến là một chỉ mục hợp lệ, [FC+1] sẽ không đủ lớn. - MSalters
Tôi đã hỏi một điều rất liên quan stackoverflow.com/questions/12972317/count-on-enum-c-automatic - sergiol


Các câu trả lời:


Không thực sự là một cách tốt để làm điều này, thông thường bạn thấy một vật phẩm phụ trong enum, tức là

enum foobar {foo, bar, baz, quz, FOOBAR_NR_ITEMS};

Vì vậy, sau đó bạn có thể làm:

int fuz[FOOBAR_NR_ITEMS];

Tuy nhiên không phải là rất tốt đẹp.

Nhưng tất nhiên bạn nhận ra rằng chỉ số lượng các mục trong một enum không an toàn, ví dụ:

enum foobar {foo, bar = 5, baz, quz = 20};

số lượng các mục sẽ là 4, nhưng các giá trị số nguyên của các giá trị enum sẽ là cách ra khỏi phạm vi chỉ mục mảng. Sử dụng các giá trị enum để lập chỉ mục mảng không an toàn, bạn nên xem xét các tùy chọn khác.

chỉnh sửa: theo yêu cầu, làm cho mục nhập đặc biệt dính ra nhiều hơn.


98
2018-01-20 15:42



Gọi nó là LAST hoặc ALWAYS_AT_END hoặc một cái gì đó không quá khó hiểu. Làm cho nó dính ra. Vì vậy, các nhà bảo trì tiếp theo không vô tình thêm các mục mới sau khi bạn kết thúc điểm đánh dấu. - Martin York
Đối với tốt hơn hoặc tệ hơn, đây là cách tiếp cận chúng tôi thực hiện trong tổ chức của mình. Chúng tôi thường gọi nó là FINAL_enumname_ENTRY, chẳng hạn như FINAL_foobar_ENTRY. Tôi cũng thấy mọi người sử dụng biến FOOBAR_COUNT const tĩnh riêng biệt được xác định ngay sau khai báo enum, một cách tiếp cận dễ bị lỗi hơn một chút. - Darryl
Ít nhất nó khá dễ dàng để thấy rằng "enum foo {a = 10, LAST}" sẽ là lẻ. Và tôi nghĩ "int arr [LAST]" sẽ là 11 mục trong trường hợp này, không phải 2, vì vậy hầu hết mã sẽ hoạt động (nhưng bạn đang lãng phí bộ nhớ trên các giá trị chỉ mục không hợp lệ) - Code Abominator


Đối với C ++, có rất nhiều kỹ thuật enum loại an toàn có sẵn và một số trong số đó (chẳng hạn như đề xuất nhưng chưa bao giờ được gửi Boost.Enum) bao gồm hỗ trợ để nhận được kích thước của một enum.

Cách tiếp cận đơn giản nhất, hoạt động trong C cũng như C ++, là áp dụng một quy ước khai báo giá trị MAX ... cho mỗi loại enum của bạn:

enum Folders { FA, FB, FC, Folders_MAX = FC };
ContainerClass *m_containers[Folders_MAX + 1];
....
m_containers[FA] = ...; // etc.

Chỉnh sửa: Về { FA, FB, FC, Folders_MAX = FC} đấu với {FA, FB, FC, Folders_MAX]: Tôi thích đặt giá trị MAX ... thành giá trị pháp lý cuối cùng của enum vì một vài lý do:

  1. Tên của hằng số kỹ thuật chính xác hơn (kể từ khi Folders_MAX cho giá trị enum tối đa có thể).
  2. Cá nhân tôi cảm thấy thích Folders_MAX = FC nổi bật so với các mục khác một chút (làm cho nó khó hơn một chút để vô tình thêm các giá trị enum mà không cập nhật giá trị tối đa, một vấn đề mà Martin York tham chiếu).
  3. GCC bao gồm các cảnh báo hữu ích như "giá trị liệt kê không được bao gồm trong chuyển đổi" cho mã như sau. Cho phép Folders_MAX == FC + 1 phá vỡ những cảnh báo đó, vì bạn kết thúc với một loạt ... Giá trị liệt kê MAX không bao giờ được bao gồm trong chuyển đổi.
chuyển đổi (thư mục)
{
  trường hợp FA: ...;
  trường hợp FB: ...;
  // Rất tiếc, đã quên FC!
}

28
2018-01-20 15:48



Giải pháp tuyệt vời mà tôi chưa bao giờ thấy trước đây. Tôi đã ở giữa đề xuất một Boost.Preprocessor hack mà tôi đã sử dụng, nhưng đây là cách thanh lịch hơn (và những gì tôi đã được tìm kiếm). - Travis Gockel
Tại sao không làm: enum Folders { FA, FB, FC, Folders_MAX }; ContainerClass *m_containers[Folders_MAX]; ? - Bill
Tôi muốn làm rõ rằng số cuối cùng là một số và tất cả chúng đều có cùng tên nhờ: struct SomeEnum { enum type {FA, FB, FC, NB__};}; - Luc Hermitte
Trên thực tế tôi cảm thấy những cảnh báo "hữu ích" là một nỗi đau đúng trong ass. Tôi thích cảnh báo tốt, tôi luôn đặt -Wall -pedantic, vv khi tôi đang phát triển, nhưng những cảnh báo này chỉ là ngu ngốc. Chỉ có một vài điều tồi tệ hơn, như đề nghị các parens cho && || và & ^ | ưu tiên điều hành. Ý tôi là, tôi nghĩ java là ngôn ngữ giữ trẻ, cái quái gì đang xảy ra với C và C ++ ... - wich
Các thư mục enum {FA, FB, FC, Folders_MIN = FA, Folders_MAX = FC}; Chỉ cần nhấn mạnh rằng nó rất hữu ích cho việc lặp lại? - gjpc


Làm thế nào về đặc điểm, trong một thời trang STL? Ví dụ:

enum Foo
{
    Bar,
    Baz
};

viết một

std::numeric_limits<enum Foo>::max()

chuyên môn hóa (có thể là constexpr nếu bạn sử dụng c ++ 11). Sau đó, trong mã thử nghiệm của bạn cung cấp bất kỳ xác nhận tĩnh nào để duy trì các ràng buộc mà std :: numeric_limits :: max () = last_item.


5
2017-12-23 13:23



Thật không may điều này sẽ không hoạt động theo câu trả lời này. - rr-
Một ví dụ cho thấy khi điều này không thành công sẽ hữu ích. - Wojciech Migda
std::numeric_limits<enum Foo>::max() luôn luôn trả về số không ... (xem câu hỏi cho câu trả lời được liên kết) Thử nghiệm trên các enums bình thường (enum Foo { ... }), enum gợi ý loại (enum class Foo : uint8_t { ... }) với gcc 5.2.0 @ Linux và MinGW 4.9.3 @ Windows. - rr-
(... và trong trường hợp std::numeric_limits<std::underlying_type<Foo>::type>::max(), nó trả về giá trị tối đa của kiểu cơ bản tức là 0xFFFFFFFF cho các số nguyên 32 bit, không hữu ích trong ngữ cảnh này.) - rr-
-1; ping tôi nếu bạn thay đổi câu trả lời, vì vậy tôi có thể hoàn tác downvote. Câu trả lời này là một quy ước tồi để làm theo. Đó là lạm dụng khái niệm numeric_limits<T>::max(). Điều duy nhất mà chức năng có thể trả về hợp lý là giá trị được liệt kê cao nhất. Nó sẽ trở lại 2, nhưng OP (trong trường hợp cụ thể này) sẽ cần nó để trả lại 3. Khi bạn có các giá trị không mặc định cho enum (FB = 2057), tất cả mọi phiên cược đều bị tắt, thậm chí không thể + 1 để hack xung quanh lỗi off-by-one. Nếu có numeric_limits<T>::number_of_elements_of_the_set() (hoặc một tên ngắn hơn), có thể được sử dụng mà không mơ hồ. - Merlyn Morgan-Graham


Thêm một mục, vào cuối enum của bạn, được gọi là Folders_MAX hoặc một cái gì đó tương tự và sử dụng giá trị này khi khởi tạo mảng của bạn.

ContainerClass* m_containers[Folders_MAX];

3
2018-01-20 15:42





Tôi thực sự không thấy bất kỳ cách nào để thực sự nhận được số lượng các giá trị trong một liệt kê trong C + +. Bất kỳ giải pháp nào trước đây đề cập đến miễn là bạn không xác định giá trị của các liệt kê nếu bạn xác định giá trị mà bạn có thể chạy vào các tình huống mà bạn tạo mảng quá lớn hoặc quá nhỏ

enum example{ test1 = -2, test2 = -1, test3 = 0, test4 = 1, test5 = 2 }

trong ví dụ này, kết quả sẽ tạo ra một mảng gồm 3 mục khi bạn cần một mảng gồm 5 mục

enum example2{ test1 , test2 , test3 , test4 , test5 = 301 }

trong ví dụ này, kết quả sẽ tạo ra một mảng gồm 301 mục khi bạn cần một mảng gồm 5 mục

Cách tốt nhất để giải quyết vấn đề này trong trường hợp chung sẽ là lặp lại thông qua các bảng liệt kê của bạn nhưng điều đó không có trong tiêu chuẩn mà theo như tôi biết


1
2018-01-12 23:59





Tôi thích sử dụng enums làm đối số cho các chức năng của mình. Đó là một phương tiện dễ dàng để cung cấp một danh sách cố định của "tùy chọn". Vấn đề với câu trả lời bình chọn hàng đầu ở đây là sử dụng điều đó, một khách hàng có thể chỉ định một "tùy chọn không hợp lệ". Là một spin off, tôi khuyên bạn nên làm cơ bản cùng một điều, nhưng sử dụng một int liên tục bên ngoài của enum để xác định số lượng của chúng.

enum foobar { foo, bar, baz, quz };
const int FOOBAR_NR_ITEMS=4;

Nó không dễ chịu, nhưng nó là một giải pháp sạch nếu bạn không thay đổi enum mà không cập nhật hằng số.


1
2017-11-13 22:14