Tôi nghĩ rằng những công việc này ngay bây giờ, bất kể bạn có sử dụng phần bổ sung của hai hay không. Vui lòng kiểm tra rộng rãi trước khi bạn sử dụng nó. Họ đưa ra kết quả sau. Mỗi dòng đưa ra một xác nhận không thành công (chỉ cần thay đổi chúng thành các ngoại lệ như bạn vui lòng)
/* unsigned -> signed, overflow */
safe_cast<short>(UINT_MAX);
/* unsigned -> unsigned, overflow */
safe_cast<unsigned char>(ULONG_MAX);
/* signed -> unsigned, overflow */
safe_cast<unsigned long>(-1);
/* signed -> signed, overflow */
safe_cast<signed char>(INT_MAX);
/* always works (no check done) */
safe_cast<long>(INT_MAX);
// giving these assertion failures results
(type)f <= (type)is_signed<To>::v_max
f <= (To)-1
f >= 0
f >= is_signed<To>::v_min && f <= is_signed<To>::v_max
Thực hiện. Đầu tiên một số tiện ích để kiểm tra các xếp hạng số nguyên (các loại có thứ hạng cao hơn sẽ có thể chứa các giá trị của các loại có thứ hạng thấp hơn, cùng một dấu hiệu. Và một số công cụ quảng cáo, để có thể tìm ra một loại an toàn chung (điều này sẽ không bao giờ mang lại một loại ký nếu một kiểu unsigned có liên quan, nếu loại ký sẽ không thể lưu trữ tất cả các giá trị của một unsigned).
/* ranks */
template<typename> struct int_rank;
#define RANK(T, I) template<> struct int_rank<T> \
{ static int const value = I; }
RANK(char, 1); RANK(unsigned char, 1); RANK(signed char, 1);
RANK(short, 2); RANK(unsigned short, 2);
RANK(int, 3); RANK(unsigned int, 3);
RANK(long, 4); RANK(unsigned long, 4);
#undef RANK
/* usual arith. conversions for ints (pre-condition: A, B differ) */
template<int> struct uac_at;
template<> struct uac_at<1> { typedef int type; };
template<> struct uac_at<2> { typedef unsigned int type; };
template<> struct uac_at<3> { typedef long type; };
template<> struct uac_at<4> { typedef unsigned long type; };
template<typename A, typename B>
struct uac_type {
static char (&f(int))[1];
static char (&f(unsigned int))[2];
static char (&f(long))[3];
static char (&f(unsigned long))[4];
typedef typename uac_at<sizeof f(0 ? A() : B())>::type type;
};
/* signed games */
template<typename> struct is_signed { static bool const value = false; };
#define SG(X, TT) template<> struct is_signed<X> { \
static bool const value = true; \
static X const v_min = TT##_MIN; \
static X const v_max = TT##_MAX; \
}
SG(signed char, SCHAR);
SG(short, SHRT);
SG(int, INT);
SG(long, LONG);
#undef SG
template<> struct is_signed<char> {
static bool const value = (CHAR_MIN < 0);
static char const v_min = CHAR_MIN; // just in case it's signed...
static char const v_max = CHAR_MAX;
};
các mẫu chuyển đổi sử dụng trong số họ, để tìm ra cho mỗi trường hợp cần phải làm gì hoặc không làm gì.
template<typename To, typename From,
bool to_signed = is_signed<To>::value,
bool from_signed = is_signed<From>::value,
bool rank_fine = (int_rank<To>::value >= int_rank<From>::value)>
struct do_conv;
/* these conversions never overflow, like int -> int,
* or int -> long. */
template<typename To, typename From, bool Sign>
struct do_conv<To, From, Sign, Sign, true> {
static To call(From f) {
return (To)f;
}
};
template<typename To, typename From>
struct do_conv<To, From, false, false, false> {
static To call(From f) {
assert(f <= (To)-1);
return (To)f;
}
};
template<typename To, typename From>
struct do_conv<To, From, false, true, true> {
typedef typename uac_type<To, From>::type type;
static To call(From f) {
/* no need to check whether To's positive range will
* store From's positive range: Because the rank is
* fine, and To is unsigned.
* Fixes GCC warning "comparison is always true" */
assert(f >= 0);
return (To)f;
}
};
template<typename To, typename From>
struct do_conv<To, From, false, true, false> {
typedef typename uac_type<To, From>::type type;
static To call(From f) {
assert(f >= 0 && (type)f <= (type)(To)-1);
return (To)f;
}
};
template<typename To, typename From, bool Rank>
struct do_conv<To, From, true, false, Rank> {
typedef typename uac_type<To, From>::type type;
static To call(From f) {
assert((type)f <= (type)is_signed<To>::v_max);
return (To)f;
}
};
template<typename To, typename From>
struct do_conv<To, From, true, true, false> {
static To call(From f) {
assert(f >= is_signed<To>::v_min && f <= is_signed<To>::v_max);
return (To)f;
}
};
template<typename To, typename From>
To safe_cast(From f) { return do_conv<To, From>::call(f); }
Nhưng bạn có thể sao chép mã bạn cần từ numeric_limits vào trình trợ giúp được tạo khuôn mẫu của riêng bạn. Chỉ định mọi thứ cho uint64 (hoặc bất kỳ kích thước tối đa cho phép nào) và so sánh trong loại đó. –
Điều đó có thể hoạt động, nhưng thực sự cần phải biết về các điều khoản cấp phép khi sao chép mã như thế này. Bên cạnh khả năng vi phạm các điều khoản, người ta có thể vô ý "lây nhiễm" mã của họ, như trường hợp với GPL. Đảm bảo cả hai giấy phép đều tương thích trước khi thực hiện loại điều này. Thông báo từ chối "Tôi không phải là luật sư" thông thường được áp dụng. – Void
Các lý do khác nhau mà bạn không thể sử dụng STL là gì? – GManNickG