numeric_cast

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.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *