Как извлечь double из stringstream


Работая над моим проектом C++, я заметил кое-что странное, играя с объектами stringstream: я не могу извлечь double из stringstream с помощью >>.

Рассмотрим следующий пример:

#include <string>
#include <sstream>

int main(int argc, const char * argv[]) {

    std::string string("1000 ; 523277527397538 ; 0.183 ; 0.453 ; 0.5 ; 0.5 ; 0.033 ; 0 ; 0 ;");
    std::stringstream stringstream(string);
    int integer;
    char character;
    double doubleprec;
    stringstream >> integer >> character;
    stringstream >> integer >> character;
    stringstream >> doubleprec >> character;
    stringstream >> doubleprec >> character;

    return 0;
}

Используя мой отладчик, я заметил, что переменная integer сначала принимает значение 1000, а затем значение 523277527397538 (Как я и ожидал), но doubleprec всегда принимает значение 0.

Почему это? Я что-то упускаю из виду в том, как работают потоки?

2 3

2 ответа:

Только первый оператор вывода потока:

stringstream >> integer >> character;

Успешно. Остальные три не связаны с тем, что ваша переменная int не может содержать значение 523277527397538. Измените его на long long:

long long integer;

Если при извлечении потока не удается поместить числовой литерал 523277527397538 в переменную, то устанавливается failbit stringstream, и последующие вызовы извлечения stringstream также завершаются неудачей. Хорошим подходом является использование оператора if при работе с потоком IO:

if (stringstream >> integer >> character){
    // success
}

Быстрая демонстрация, чтобы усилить ответ Рона: (c++14)

#include <string>
#include <sstream>
#include <iostream>


int main(int argc, const char * argv[]) {


    std::string string("1000 ; 523277527397538 ; 0.183 ; 0.453 ; 0.5 ; 0.5 ; 0.033 ; 0 ; 0 ;");
    std::stringstream stringstream(string);

    auto okfail = [](auto&& b) {
        if (not b) return std::string("fail");
        return std::string("ok");
    };

    auto read = [&](auto&& var, auto&& f) {
        std::cout << "reading " << var << ". Stream is " << okfail(stringstream) << std::endl;
        f();
        std::cout << "read " << var << ". Stream is " << okfail(stringstream) << std::endl;
    };

    int integer1;
    int integer2;
    char character;
    double doubleprec1, doubleprec2;
    read("integer1", [&] { stringstream >> integer1 >> character; });
    read("integer2", [&] { stringstream >> integer2 >> character; });
    read("doubleprec1", [&] { stringstream >> doubleprec1 >> character; });
    read("doubleprec2", [&] { stringstream >> doubleprec2 >> character; });

    std::cout << integer1<< " " << integer2 << " " << doubleprec1 << " " << doubleprec2 << " " << std::endl;
    return 0;
}

Пример вывода (imac 64-разрядный):

reading integer1. Stream is ok
read integer1. Stream is ok
reading integer2. Stream is ok
read integer2. Stream is fail
reading doubleprec1. Stream is fail
read doubleprec1. Stream is fail
reading doubleprec2. Stream is fail
read doubleprec2. Stream is fail
1000 2147483647 0 0 

Теперь измените integer2 на long int:

reading integer1. Stream is ok
read integer1. Stream is ok
reading integer2. Stream is ok
read integer2. Stream is ok
reading doubleprec1. Stream is ok
read doubleprec1. Stream is ok
reading doubleprec2. Stream is ok
read doubleprec2. Stream is ok
1000 523277527397538 0.183 0.453