Nếu bạn sẵn sàng viết mã "nghịch ngợm" khiến các nhà phát triển khác khóc, thì có. Hãy thử điều này:
#define ENUM(name, ...) typedef enum { M_FOR_EACH(ENUM_IDENTITY, __VA_ARGS__) } name; \
char * name ## _DEBUGSTRINGS [] = { M_FOR_EACH(ENUM_STRINGIZE, __VA_ARGS__) };
#define ENUM_IDENTITY(A) A,
#define ENUM_STRINGIZE(A) #A,
ENUM(MyEnum,
foo, bar, baz, boo
)
Bạn rõ ràng cần một macro riêng để thực hiện công việc này. Dưới đây là một đơn giản:
#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)
#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
#define M_FOR_EACH_6(ACTN, E, ...) ACTN(E) M_FOR_EACH_5(ACTN, __VA_ARGS__)
#define M_FOR_EACH_7(ACTN, E, ...) ACTN(E) M_FOR_EACH_6(ACTN, __VA_ARGS__)
#define M_FOR_EACH_8(ACTN, E, ...) ACTN(E) M_FOR_EACH_7(ACTN, __VA_ARGS__)
#define M_FOR_EACH_9(ACTN, E, ...) ACTN(E) M_FOR_EACH_8(ACTN, __VA_ARGS__)
#define M_FOR_EACH_10(ACTN, E, ...) ACTN(E) M_FOR_EACH_9(ACTN, __VA_ARGS__)
Nó nên được rõ ràng làm thế nào để kéo dài mà vòng lặp để có một giới hạn trên dài hơn, nhưng ... cân nhắc không gian cho câu trả lời này. Vòng lặp có thể có khả năng miễn là bạn sẵn sàng sao chép và dán thêm các lần lặp vào bit này.
Đối với bản dựng không gỡ lỗi, hãy #ifdef chọn phiên bản ENUM không có dòng thứ hai.
EDIT: Để ăn cắp initialisers ý tưởng thiết kế từ teppic, đây là một phiên bản thậm chí khủng khiếp hơn mà cũng làm việc với những người không theo lệnh initialiser giá trị:
#define ENUM(name, ...) typedef enum { M_FOR_EACH(ENUM_ENAME, __VA_ARGS__) } name; \
char * name ## _DEBUGSTRINGS [] = { M_FOR_EACH(ENUM_ELEM, __VA_ARGS__) };
#define ENUM_ENAME(A) M_IF(M_2ITEMS(M_ID A), (M_FIRST A = M_SECOND A), (A)),
#define ENUM_ELEM(A) M_IF(M_2ITEMS(M_ID A), ([M_FIRST A] = M_STR(M_FIRST A)), ([A] = M_STR(A))),
#define M_STR(A) M_STR_(A)
#define M_STR_(A) #A
#define M_IF(P, T, E) M_CONC(M_IF_, P)(T, E)
#define M_IF_0(T, E) M_ID E
#define M_IF_1(T, E) M_ID T
#define M_2ITEMS(...) M_2I_(__VA_ARGS__, 1, 0)
#define M_2I_(_2, _1, N, ...) N
#define M_FIRST(A, ...) A
#define M_SECOND(A, B, ...) B
#define M_ID(...) __VA_ARGS__
ENUM(MyEnum,
foo, bar, baz, boo
)
ENUM(NotherEnum,
A, B, (C, 12), D, (E, 8)
)
tôi không thể đảm bảo an toàn cá nhân của bạn nếu bạn sử dụng loại điều này trong mã mà người khác phải duy trì.
Theo như tôi biết không có cách nào để làm điều này, viết tắt phương pháp của riêng bạn, như bạn đã làm. –
Thật không may là không thể vì tên enum không có sẵn trong quá trình biên dịch. – iDev
có thể trùng lặp của [Convert target-c typedef thành chuỗi tương đương] (http://stackoverflow.com/questions/1094984/convert-objective-c-typedef-to-its-string-equivalent). Bạn có thể sử dụng một trong các phương pháp được đề xuất ở đó. – iDev