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)

Dodaj komentarz

/dozwolony markdown/

/nie zostanie opublikowany/