Hôm nay tôi mới phát minh lại bánh xe này và nghĩ rằng mình sẽ chia sẻ nó.
Việc triển khai này không yêu cầu bất kỳ thay đổi nào đối với mã xác định các hằng số, có thể là liệt kê hoặc#define
s hoặc bất kỳ thứ gì khác chuyển thành số nguyên - trong trường hợp của tôi, tôi đã xác định các ký hiệu theo các ký hiệu khác. Nó cũng hoạt động tốt với các giá trị thưa thớt. Nó thậm chí còn cho phép nhiều tên cho cùng một giá trị, luôn trả về tên đầu tiên. Nhược điểm duy nhất là nó yêu cầu bạn tạo một bảng các hằng số, có thể trở nên lỗi thời khi các hằng số mới được thêm vào chẳng hạn.
struct IdAndName
{
int id;
const char * name;
bool operator<(const IdAndName &rhs) const { return id < rhs.id; }
};
#define ID_AND_NAME(x) { x, #x }
const char * IdToName(int id, IdAndName *table_begin, IdAndName *table_end)
{
if ((table_end - table_begin) > 1 && table_begin[0].id > table_begin[1].id)
std::stable_sort(table_begin, table_end);
IdAndName searchee = { id, NULL };
IdAndName *p = std::lower_bound(table_begin, table_end, searchee);
return (p == table_end || p->id != id) ? NULL : p->name;
}
template<int N>
const char * IdToName(int id, IdAndName (&table)[N])
{
return IdToName(id, &table[0], &table[N]);
}
Ví dụ về cách bạn sử dụng nó:
static IdAndName WindowsErrorTable[] =
{
ID_AND_NAME(INT_MAX), // flag value to indicate unsorted table
ID_AND_NAME(NO_ERROR),
ID_AND_NAME(ERROR_INVALID_FUNCTION),
ID_AND_NAME(ERROR_FILE_NOT_FOUND),
ID_AND_NAME(ERROR_PATH_NOT_FOUND),
ID_AND_NAME(ERROR_TOO_MANY_OPEN_FILES),
ID_AND_NAME(ERROR_ACCESS_DENIED),
ID_AND_NAME(ERROR_INVALID_HANDLE),
ID_AND_NAME(ERROR_ARENA_TRASHED),
ID_AND_NAME(ERROR_NOT_ENOUGH_MEMORY),
ID_AND_NAME(ERROR_INVALID_BLOCK),
ID_AND_NAME(ERROR_BAD_ENVIRONMENT),
ID_AND_NAME(ERROR_BAD_FORMAT),
ID_AND_NAME(ERROR_INVALID_ACCESS),
ID_AND_NAME(ERROR_INVALID_DATA),
ID_AND_NAME(ERROR_INVALID_DRIVE),
ID_AND_NAME(ERROR_CURRENT_DIRECTORY),
ID_AND_NAME(ERROR_NOT_SAME_DEVICE),
ID_AND_NAME(ERROR_NO_MORE_FILES)
};
const char * error_name = IdToName(GetLastError(), WindowsErrorTable);
Các IdToName
chức năng dựa vàostd::lower_bound
để làm tra cứu nhanh chóng, đòi hỏi các bảng được sắp xếp. Nếu hai mục đầu tiên trong bảng không theo thứ tự, hàm sẽ tự động sắp xếp.
Chỉnh sửa: Một nhận xét khiến tôi nghĩ đến một cách khác để sử dụng cùng một nguyên tắc. Macro đơn giản hóa việc tạo một switch
câu lệnh lớn .
#define ID_AND_NAME(x) case x: return #x
const char * WindowsErrorToName(int id)
{
switch(id)
{
ID_AND_NAME(ERROR_INVALID_FUNCTION);
ID_AND_NAME(ERROR_FILE_NOT_FOUND);
ID_AND_NAME(ERROR_PATH_NOT_FOUND);
ID_AND_NAME(ERROR_TOO_MANY_OPEN_FILES);
ID_AND_NAME(ERROR_ACCESS_DENIED);
ID_AND_NAME(ERROR_INVALID_HANDLE);
ID_AND_NAME(ERROR_ARENA_TRASHED);
ID_AND_NAME(ERROR_NOT_ENOUGH_MEMORY);
ID_AND_NAME(ERROR_INVALID_BLOCK);
ID_AND_NAME(ERROR_BAD_ENVIRONMENT);
ID_AND_NAME(ERROR_BAD_FORMAT);
ID_AND_NAME(ERROR_INVALID_ACCESS);
ID_AND_NAME(ERROR_INVALID_DATA);
ID_AND_NAME(ERROR_INVALID_DRIVE);
ID_AND_NAME(ERROR_CURRENT_DIRECTORY);
ID_AND_NAME(ERROR_NOT_SAME_DEVICE);
ID_AND_NAME(ERROR_NO_MORE_FILES);
default: return NULL;
}
}