2の補数を使用するかどうかにかかわらず、これらの作業は今や考えられます。あなたがそれを使用する前に広範囲にテストしてください。彼らは次の結果を出します。各行は、1つのアサーションの失敗を与える
/* 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
実装(ちょうどあなたしてくださいとして例外にそれらを変更します)。最初に、整数ランクをチェックするいくつかのユーティリティ(ランクの高い型は、同じ符号を与えられた、より低いランクの型の値を含むことができます)、いくつかのプロモーションツールは、共通の安全な型を見つけることができます符号なしの型が関与している場合はsigned型は、符号なしの1のすべての値を格納することができません場合。
/* 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;
};
変換テンプレートは、それぞれに把握するために、それらを利用して)、符号付きの型をもたらします何が行われる必要があるか、行われない場合があります。
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); }
しかし、必要なコードをnumeric_limitsから自分のテンプレートヘルパーにコピーすることができます。すべてをuint64(または最大許容サイズが何であれ)に割り当て、そのタイプ内の比較を行います。 –
これはうまくいくかもしれませんが、実際にはこのようなコードをコピーする際にライセンス条項を認識する必要があります。潜在的に違反することに加えて、GPLの場合のように、誤ってコードに「感染する」可能性があります。この種の作業を行う前に、両方のライセンスが互換性があることを確認してください。通常の "私は弁護士ではありません"という免責事項が適用されます。 – Void
STLを使用できないさまざまな理由は何ですか? – GManNickG