Việc sử dụng boost :: preprocessor có thể trở thành một giải pháp thanh lịch như sau:
Bước 1: bao gồm tệp tiêu đề:
#include "EnumUtilities.h"
Bước 2: Khai báo đối tượng liệt kê theo cú pháp sau:
MakeEnum( TestData,
(x)
(y)
(z)
);
Bước 3: Sử dụng dữ liệu của bạn:
Nhận số phần tử:
td::cout << "Number of Elements: " << TestDataCount << std::endl;
Lấy chuỗi liên kết:
std::cout << "Value of " << TestData2String(x) << " is " << x << std::endl;
std::cout << "Value of " << TestData2String(y) << " is " << y << std::endl;
std::cout << "Value of " << TestData2String(z) << " is " << z << std::endl;
Nhận giá trị enum từ chuỗi được liên kết:
std::cout << "Value of x is " << TestData2Enum("x") << std::endl;
std::cout << "Value of y is " << TestData2Enum("y") << std::endl;
std::cout << "Value of z is " << TestData2Enum("z") << std::endl;
Điều này trông gọn gàng và nhỏ gọn, không có thêm tệp nào để bao gồm. Đoạn mã tôi đã viết trong EnumUtilities.h như sau:
#include <boost/preprocessor/seq/for_each.hpp>
#include <string>
#define REALLY_MAKE_STRING(x) #x
#define MAKE_STRING(x) REALLY_MAKE_STRING(x)
#define MACRO1(r, data, elem) elem,
#define MACRO1_STRING(r, data, elem) case elem: return REALLY_MAKE_STRING(elem);
#define MACRO1_ENUM(r, data, elem) if (REALLY_MAKE_STRING(elem) == eStrEl) return elem;
#define MakeEnum(eName, SEQ) \
enum eName { BOOST_PP_SEQ_FOR_EACH(MACRO1, , SEQ) \
last_##eName##_enum}; \
const int eName##Count = BOOST_PP_SEQ_SIZE(SEQ); \
static std::string eName##2String(const enum eName eel) \
{ \
switch (eel) \
{ \
BOOST_PP_SEQ_FOR_EACH(MACRO1_STRING, , SEQ) \
default: return "Unknown enumerator value."; \
}; \
}; \
static enum eName eName##2Enum(const std::string eStrEl) \
{ \
BOOST_PP_SEQ_FOR_EACH(MACRO1_ENUM, , SEQ) \
return (enum eName)0; \
};
Có một số hạn chế, tức là những hạn chế của boost :: tiền xử lý. Trong trường hợp này, danh sách các hằng số không được lớn hơn 64 phần tử.
Theo cùng một logic, bạn cũng có thể nghĩ để tạo enum thưa thớt:
#define EnumName(Tuple) BOOST_PP_TUPLE_ELEM(2, 0, Tuple)
#define EnumValue(Tuple) BOOST_PP_TUPLE_ELEM(2, 1, Tuple)
#define MACRO2(r, data, elem) EnumName(elem) EnumValue(elem),
#define MACRO2_STRING(r, data, elem) case EnumName(elem): return BOOST_PP_STRINGIZE(EnumName(elem));
#define MakeEnumEx(eName, SEQ) \
enum eName { \
BOOST_PP_SEQ_FOR_EACH(MACRO2, _, SEQ) \
last_##eName##_enum }; \
const int eName##Count = BOOST_PP_SEQ_SIZE(SEQ); \
static std::string eName##2String(const enum eName eel) \
{ \
switch (eel) \
{ \
BOOST_PP_SEQ_FOR_EACH(MACRO2_STRING, _, SEQ) \
default: return "Unknown enumerator value."; \
}; \
};
Trong trường hợp này, cú pháp là:
MakeEnumEx(TestEnum,
((x,))
((y,=1000))
((z,))
);
Cách sử dụng tương tự như trên (trừ hàm eName ## 2Enum mà bạn có thể thử ngoại suy từ cú pháp trước đó).
Tôi đã thử nghiệm nó trên mac và linux, nhưng lưu ý rằng boost :: tiền xử lý có thể không hoàn toàn di động.