2015-05-11 18 views
6

Bir Standart kütüphane arayan veya kayıpsız başka ilkel tip bir numara döküm ve bir şekilde dökme kayıpsız olup olmadığını bana bilgi (ya da değilse bir istisna) olabilir işlevini Boost duyuyorum.Takviye mi yoksa Standart Kitaplık dökümün kayıpsız olup olmadığını kontrol etmenin bir yolunu sunuyor mu?

auto x = lossless_cast<double>(1u); // ok, double can represent 1 
auto x = lossless_cast<int>(1.2); // fail, int can't represent 1.2 
auto x = lossless_cast<int>(1E200); // fail, int can't represent 1E200 

boost::numeric_cast hedef türü sayısal aralık dışında düşmek atmalarını bulacaktır ki yakın geliyor, ama onlar kayıpsız ama içinde hedef türü ise (gözlerimi göremiyorum: İşte bazı örnekler 2. örnek).

bir SO question for the C language which provides some hand-rolled solutions to this problem yok, ama temelde aşağıdaki işlevselliği ile, bir boost veya Standart Kütüphane çözümden sonra duyuyorum:

template <typename out, typename in> 
out lossless_cast(in in_value) 
{ 
    out out_value = static_cast<out>(in_value); 

    if (static_cast<in>(out_value) != in_value) 
    throw; // some exception 

    return out_value; 
} 

bu işlevsellik var mı?

+4

döküm sonra önce ve eşitlik için sonra karşılaştırır gerçekleştiren bir fonksiyon yazın. –

+3

Dökme gidiş gelişsiz bir çözüm bekliyorsanız, fark ettiğinizden daha zor bir sorun olabilir. Örneğin bir float 16,777,217'yi temsil edemez. – zneak

+2

@IgorTandetnik: iyi bir fikir değil - bazı durumlarda * tanımsız davranış * verir (örn 'lossless_cast (1E200 için); söz konusu' vaka). –

cevap

3

ben çok Standardında önceden haddelenmiş bir şey olmadığından emin ve artırımı şeyin farkında değilim ama büyük bir kütüphane var. Herhangi uygulama kullanarak döküm 4.9 [conv.fpint] başına dışarı aralık değerleri için tanımsız davranış dikkatli olmak zorunda, ama boost::numeric_cast<> görünüşte o kolları olarak şunu kullanabilirsiniz:

template <typename U, typename T> 
inline U is_lossless(T t) 
{ 
    U u = boost::numeric_cast<U>(t); 
    T t2 = boost::numeric_cast<T>(u); // throw if now out-of-range 
    if (t != t2) 
     throw whatever-you-like; 
    return u; 
} 

ihtiyaç için numeric_cast<>t2 kurtarma az açıktır: o başarılı ama bir int64_t için aralık dışında olandan y ayrılmaz bir değerle yaklaşık olarak int64_t xdouble y için diyelim ki bir değer döküm için mümkün olduğu u, aralıkta hala olmasını sağlar, öyle double'dan geri döndürme tanımsız bir davranışa sahiptir.

yasallığı/yukarıda sağlamlığı boost::numeric_cast<> doğru doğrulamadım tanımsız davranış, kaçınır gerektirir.

+0

“ boost :: numeric_cast' ”in niyetinin gayet eminim UB vakalarından kaçınmak için. Mevcut uygulamada gerçekten başarılı olup olmadığı daha zordur; http://stackoverflow.com/q/25857843/ – Nemo

+0

@Nemo'ya bakın: Eğer bu onların niyetiydi, umarım çabuk (CPU döngüleri anlamında) yapmak zor olabilir ve tanımlanmamış davranışları bulmuş olabilirler. Hedeflenen yüklenen belirli CPU'larda, taşınabilirlik gereksinimleri için, tüm olası hedefler arasında Standart olarak yetkilendirilmiş taşınabilir olmaksızın kabul edilebilir. Bilgisayarımdaki kodu yeni aldım ve bağlantınızı kontrol edeceğim - şerefe. –

+1

'T' türünün parametreden çıkarılabildiğinden, 'first * şablon parametresinin typename U' türünde bir değer olur muydu? Bu, hangi destek ve çekirdek dilin sağladığına benzeyen bir "döküm" sözdizimine izin verir. –

İlgili konular