В примере 3.7 я написал простую функцию sciToDub, принимающую параметр типа stringи возвращающую содержащийся в ней double, если он допустим. В sciToDubя использую stringstreamследующим образом.
stringstream ss(str); // Конструирование из строки типа string
double d = 0;
ss >> d;
if (ss.fail()) {
string s = "Невозможно отформатировать ";
s += str;
s += " как число!";
throw (s);
}
return (d);
Наиболее важной частью здесь является то, что все, что требуется сделать, — это использовать для чтения из строкового потока в doubleоператор сдвига вправо ( >>), как это делается при чтении из cin.
Ну, это не совсем все , что требуется сделать. Если в stringstreamзаписано значение, которое не может быть записано в переменную в правой части оператора >>, то для потока будет выставлен бит fail. Этот бит можно проверить с помощью функции-члена fail(на самом деле это функция-член basic_ios, который является родительским классом для stringstream). Кроме того, переменная справа от оператора >>в случае ошибки значения не меняет.
Однако с целью обобщения можно избежать написания отдельных версий sciToDubдля типов int, float, doubleи чего-либо еще, что может потребоваться преобразовать, если написать шаблон функции. Рассмотрим такую новую версию.
template
T strToNum(const string& str) {
stringstream ss(str);
T tmp;
ss >> tmp;
if (ss.fail()) {
string s = "Невозможно отформатировать ";
s += str;
s += " как число!";
throw (s);
}
return (tmp);
}
Теперь, чтобы преобразовать stringв числовой тип, можно сделать так.
double d = strToNum("7.0");
float f = strToNum("7.0");
int i = strToNum("7.0");
Также параметром шаблона можно сделать тип символов, но это очень просто сделать, так что я оставляю это в качестве вашего упражнения.
Смотри также
Рецепт 3.2.
3.6. Преобразования между числовыми типами
Проблема
Имеется число одного типа и требуется преобразовать его в другой, как intв shortили наоборот, но при этом необходимо перехватывать все ошибки переполнения (overflow) или потери значимости (underflow), возникающие при работе программы.
Решение
Используйте шаблон класса numeric_castBoost. Он выполняет проверки, которые при переполнениях переменной, принимающей значение, или других ошибках выбрасывают исключение типа bad_numeric_cast. Пример 3.8 показывает, как это выполняется.
Пример 3.8. Безопасное преобразование чисел
#include
#include
using namespace std;
using boost::numeric_cast;
using boost::bad_numeric_cast;
int main() {
// Целые типы
try {
int i = 32767;
short s = numeric_cast(i);
cout << "s = " << s << endl;
i++; // Теперь i выходит за диапазон (если sizeof(short) равен 2)
s = numeric__cast(i);
} catch (bad_numeric_cast& e) {
cerr << e.what() << endl;
}
try {
int i = 300;
unsigned int ui = numeric_cast(i);
cout << ui << endl; // Прекрасно
i *= -1;
ui = numeric_cast(i); // i отрицателен!
} catch (bad_numeric_cast& e) {
cerr << e.what() << endl;
}
try {
double d = 3.14.
int i = numeric_cast(d);
i = numeric_cast(d); // Это отрезает 0.14!
cout << i << endl; // i = 3
} catch (bad_numeric_cast& e) {
cerr << e.what( ) << endl;
}
}
Обсуждение
Вы, вероятно, знаете, что базовые типы C++ имеют различные размеры. Стандарт C++ содержит жесткие указания по относительному размеру типов: intвсегда не короче, чем short int, но он не указывает абсолютных размеров. Это означает, что если взять long intи попытаться записать его значение в shortили попытаться поместить intв unsigned int, то информация о значении переменной-источника, такая как знак или даже часть числового значения, может быть потеряна.
Только знания, что это может привести к проблемам, не достаточно. Вы можете быть ограничены жесткими требованиями по объему и не захотите использовать четыре байта для long, когда можно обойтись двумя байтами для short(если ваша платформа на самом деле использует такие размеры, что очень распространено, но не гарантируется). Из-за ограничений по объему может возникнуть желание попробовать хранить значения в наименьших возможных типах. Если вы любите приключения, но вам нужна страховка, для перехвата потерь данных при работе программы используйте numeric_castиз Boost.
Читать дальше