CashCow giới thiệu a decent answer cho câu hỏi này: thật đơn giản để viết một hàm tùy chỉnh để thực hiện một phép chọn đã chọn.
Thật không may, nó cũng có rất nhiều công việc và bạn phải đảm bảo nó được đồng bộ hóa với điều tra để danh sách điều tra trong định nghĩa liệt kê giống như danh sách liệt kê trong hàm đã chọn. Bạn cũng phải viết một trong những điều này cho mỗi điều tra mà bạn muốn để có thể thực hiện một kiểm tra diễn viên.
Thay vì thực hiện tất cả công việc thủ công này, chúng tôi có thể tự động tạo tất cả mã này bằng cách sử dụng bộ tiền xử lý (với một chút trợ giúp từ thư viện bộ xử lý tăng cường). Đây là một macro tạo ra một định nghĩa liệt kê cùng với một hàm checked_enum_cast
. Nó có thể là một chút đáng sợ tìm kiếm (macro thế hệ mã thường là khủng khiếp để xem xét), nhưng nó là một kỹ thuật cực kỳ hữu ích để làm quen với.
#include <stdexcept>
#include <boost/preprocessor.hpp>
// Internal helper to provide partial specialization for checked_enum_cast
template <typename Target, typename Source>
struct checked_enum_cast_impl;
// Exception thrown by checked_enum_cast on cast failure
struct invalid_enum_cast : std::out_of_range
{
invalid_enum_cast(const char* s)
: std::out_of_range(s) { }
};
// Checked cast function
template <typename Target, typename Source>
Target checked_enum_cast(Source s)
{
return checked_enum_cast_impl<Target, Source>::do_cast(s);
}
// Internal helper to help declare case labels in the checked cast function
#define X_DEFINE_SAFE_CAST_CASE(r, data, elem) case elem:
// Macro to define an enum with a checked cast function. name is the name of
// the enumeration to be defined and enumerators is the preprocessing sequence
// of enumerators to be defined. See the usage example below.
#define DEFINE_SAFE_CAST_ENUM(name, enumerators) \
enum name \
{ \
BOOST_PP_SEQ_ENUM(enumerators) \
}; \
\
template <typename Source> \
struct checked_enum_cast_impl<name, Source> \
{ \
static name do_cast(Source s) \
{ \
switch (s) \
{ \
BOOST_PP_SEQ_FOR_EACH(X_DEFINE_SAFE_CAST_CASE, 0, enumerators) \
return static_cast<name>(s); \
default: \
throw invalid_enum_cast(BOOST_PP_STRINGIZE(name)); \
} \
return name(); \
} \
};
Đây là cách bạn sẽ sử dụng điều đó với CardColor
ví dụ của bạn:
DEFINE_SAFE_CAST_ENUM(CardColor, (HEARTS) (CLUBS) (SPADES) (DIAMONDS))
int main()
{
checked_enum_cast<CardColor>(1); // ok
checked_enum_cast<CardColor>(400); // o noez! an exception!
}
Dòng đầu tiên thay thế định nghĩa enum CardColor ...
của bạn; nó xác định việc liệt kê và cung cấp một chuyên môn cho phép bạn sử dụng checked_enum_cast
để truyền các số nguyên đến CardColor
.
Điều này có thể trông giống như rất nhiều rắc rối chỉ để có được một chức năng đúc kiểm tra cho enums của bạn, nhưng kỹ thuật này là rất hữu ích và mở rộng. Bạn có thể thêm các chức năng làm đủ mọi thứ. Ví dụ, tôi có một hàm tạo các hàm để chuyển đổi các kiểu liệt kê thành và từ các biểu diễn chuỗi và các hàm thực hiện một số chuyển đổi và kiểm tra khác mà tôi sử dụng cho hầu hết các liệt kê của mình.
Hãy nhớ rằng, bạn phải viết và gỡ lỗi macro lớn, xấu xí này một lần, sau đó bạn có thể sử dụng nó ở mọi nơi.
Khi thời gian chạy hoặc biên dịch? – CashCow
Ngoài "không làm điều đó"? –
@CashCow: tốt, cả hai! Tôi đã cập nhật câu hỏi của mình. –