Wzorzec numeric_cast
• tech • 253 słowa • 2 minuty czytania
Korzystając z wzorca numeric_limits
, o którym wspomniałem w poprzedniej notce i informacjach o min/max wartości danego typu numerycznego, można w bardzo łatwy sposób stworzyć sobie bezpieczny, odporny na underflow/overflow, “operator” - wzorzec do konwersji wartości liczbowych pomiędzy poszczególnymi typami numerycznymi.
template <typename TargetType, typename SourceType>
inline TargetType numeric_cast(SourceType arg) {
if (arg < std::numeric_limits<TargetType>::min())
throw std::underflow_error("bad numeric cast");
if (arg > std::numeric_limits<TargetType>::max())
throw std::overflow_error("bad numeric cast");
return static_cast<TargetType>(arg);
}
Drugi typ argumentu wzorca można pominąć, zostanie on wydedukowany przez kompilator na podstawie typu argumentu przekazanego do funkcji, więc konstrukcja ta przyjmuje prostą postać podobną do wbudowanych operatorów rzutowania:
try {
char c = 100;
int i = -129;
unsigned int ui = 12345;
long long l = 453232;
c = numeric_cast<char>(i); // overflow_error
i = numeric_cast<int>(c);
i = numeric_cast<int>(ui); // underflow_error
l = numeric_cast<long long>(i);
} catch (const std::underflow_error& e) {
std::cout << "underflow_error: " << e.what() << endl;
} catch (const std::overflow_error& e) {
std::cout << "overflow_error: " << e.what() << endl;
}
W rzeczywistości konstrukcja takiego “operatora” nie jest taka prosta jak się może wydawać i powyższy program nie zadziała tak jak można byłoby się spodziewać (według podanych komentarzy w przykładzie), a dlaczego nie to zostawiam do przemyślenia ;)
Trzeba rozważyć wiele przypadków, mozliwości i problemów, o czym można się przekonać oddając się lekturze topicu Rzutowanie sprawdzające zakresy z pl.comp.lang.c.
Swoja drogą boost zawiera w swoich zbiorach numerycznych konwerterów własny, bezpieczny numeric_cast i chyba najrozsądniej, jeśli już trzeba to jego używać. Jego konstrukcja opiera się na podobnej do przedstawionej wyżej koncepcji.
Komentarze (0)