Подтвердить что ты не робот

Как проверить, является ли переменная StringStream пустой/пустой?

Просто быстрый вопрос, ребята. До сих пор безрезультатно.

Немного больше информации здесь:

stringstream report_string;

report_string << "some string here...";

В моем коде есть различные условия для присвоения значений переменной report_string.

Я хотел бы проверить, было ли ему присвоено значение или нет.

4b9b3361

Ответ 1

myStream.rdbuf()->in_avail() можно использовать для подсчета количества доступных символов, готовых для чтения из stringstream, вы можете использовать его для проверки того, является ли ваш stringstream "пустым". Я предполагаю, что вы на самом деле не пытаетесь проверить значение null.

Например, если вы хотите извлечь int из stringstream, а затем посмотреть, есть ли какие-либо оставшиеся символы (т.е. не числовые), вы можете проверить, если myStream.rdbuf()->in_avail() == 0.

Это похоже на то, что вы пытаетесь сделать? Я не уверен, есть ли лучшие способы, но я делал это в прошлом, и это работало хорошо для меня.

https://en.cppreference.com/w/cpp/io/basic_streambuf/in_avail

ОБНОВЛЕНИЕ: Я вижу, вы только что обновили свой вопрос, как я опубликовал.

Ответ 2

Легкая проверка заключается в том, чтобы увидеть, является ли содержимое строки потока пустым или нет:

#include<assert.h>
#include<sstream>

int main(){
std::stringstream report_string;
report_string << ""; // an empty strin g

//emptiness check of stringstream
assert(report_string.str().empty());
}

Ответ 3

Один из способов: проверить размер внутренней строки и сравнить с нулем. Обратите внимание, что это отличается от myStream.rdbuf()->in_avail(), как предлагает AusCBlock; in_avail() может возвращать значение, отличное от фактического размера потока (если, например, внутренний буфер представлен несколькими несмежными блоками памяти). В частности, in_avail() может, в принципе, возвращать ноль в непустых буферах (возможно, спецификация stringbuf ограничивает это дальше, я не проверял подробно).

Ответ 4

Этот метод эффективен и должен работать с выходными строками:

ostringstream report_string;

if (report_string.tellp() == 0) {
    // do something
}

Ответ 5

Вместо этого используйте eof().

Пример кода:

stringstream report_string;
if ( !(report_string.eof()) ) 
    cout << "report_string EMPTY! \n";

Ответ 6

Это обычно разумно и читаемо использовать...

report_string.str().empty()

... но это может включать динамическое распределение и копирование всей строки во временное, только для того, чтобы быть выброшенным.

Если производительность важна, другая опция...

report_string.peek() == decltype(report_string)::traits_type::eof()
  • это ищет символ , еще не извлеченный из потока, игнорируя вход, который уже был успешно проанализирован/извлечен

    • который отличается от тестирования report_string.str().empty(), который все еще "видит" уже извлеченный вход
  • если предыдущий синтаксический анализ оставил поток в состоянии fail у вас нет clear() ed, это вернет eof(), независимо от того, есть ли еще неэкстрактивные символы

Ответ 7

Как насчет другого подхода?

Если вы создадите опционный тип ostringstream, вы можете проверить его назначение перед его использованием.

Представьте себе класс под названием lazy<>, который лениво конструирует объект по мере необходимости, тогда мы могли бы сделать это:

int main()
{
    using namespace std;

    auto oss1 = lazy<std::ostringstream>();
    auto oss2 = lazy<std::ostringstream>();

    use(oss1) << "Hello";

    if (oss1) cout << use(oss1).str() << endl;
    if (oss2) cout << use(oss2).str() << endl;

    if_used(oss1, [](auto& ss) { cout << ss.str() << endl; });
    if_used(oss2,
            [](auto& ss) { cout << ss.str() << endl; },
            [](auto& oss) { cout << "oss2 is not used" << endl; });

    use(oss2) << "Goodbye";
    if_used(oss2, [](auto& ss) { cout << ss.str() << endl; });

    return 0;
}

используя этот вывод:

Hello
Hello
oss2 is not used
Goodbye

Преимущества:

  • нет избыточной конструкции stringstream, если не используется.

  • optional предоставляет исключение, если впоследствии используется неиспользуемый строковый поток (через константную ссылку)

Полный пример ниже с настраиваемым конструктором:

Я использовал std::experimental для optional, но вы могли бы просто использовать boost::optional.

#include <iostream>
#include <experimental/optional>
#include <utility>
#include <type_traits>
#include <sstream>

using std::experimental::optional;

namespace detail {
    template<class T, class Constructor>
    struct lazy final
    {
        template<class Con , std::enable_if_t< not std::is_same<std::decay_t<Con>, lazy>::value > * = nullptr>
        lazy(Con&& con)
        : _constructor(std::forward<Con>(con))
        {}

        T& get() {
            if (not bool(_opt)) {
                _opt = _constructor();
            }
            return *_opt;
        }

        const T& get() const {
            return *_opt;
        }

        bool used() const {
            return bool(_opt);
        }

        operator bool() const {
            return used();
        }

    private:
        Constructor _constructor;
        optional<T> _opt;
    };

    template<class T>
    struct default_construct {
        T operator()() const { return T(); }
    };

    struct no_action {
        template<class T>
        void operator()(T&) const { }
    };
}


template<class T, class Constructor = detail::default_construct<T> >
auto lazy(Constructor&& con = detail::default_construct<T>())
{
    return detail::lazy<T, std::decay_t<Constructor>>(std::forward<Constructor>(con));
}

template<class T, class Constructor>
auto& use(detail::lazy<T, Constructor>& l)
{
    return l.get();
}

template<class T, class Constructor>
auto& use(const detail::lazy<T, Constructor>& l)
{
    return l.get();
}

template<class T, class Constructor, class F, class Else = detail::no_action>
void if_used(detail::lazy<T, Constructor>& l, F&& f, Else&& e = detail::no_action())
{
    if (l.used())
        f(l.get());
    else
        e(l);
}

template<class T, class Constructor, class F, class Else = detail::no_action>
void if_used(const detail::lazy<T, Constructor>& l, F&& f, Else&& e)
{
    if (l.used())
        f(l.get());
    else
        e(l);
}

int main()
{
    using namespace std;

    auto oss1 = lazy<std::ostringstream>();
    auto oss2 = lazy<std::ostringstream>();

    use(oss1) << "Hello";

    if (oss1) cout << use(oss1).str() << endl;
    if (oss2) cout << use(oss2).str() << endl;

    if_used(oss1, [](auto& ss) { cout << ss.str() << endl; });
    if_used(oss2,
            [](auto& ss) { cout << ss.str() << endl; },
            [](auto& oss) { cout << "oss2 is not used" << endl; });

    use(oss2) << "Goodbye";
    if_used(oss2, [](auto& ss) { cout << ss.str() << endl; });

    return 0;
}

Ответ 8

Я знаю, что этот вопрос очень старый и на него уже дан ответ, но в зависимости от ситуации может быть еще один подход, который стоит рассмотреть:

Когда вы проверяете, является ли поток строк пустым, вы должным образом намереваетесь что-то делать либо с отдельными строками, либо с каждой строкой в потоке строк; таким образом, вы, скорее всего, будете использовать оператор >> или std::getline для stringstream... и если поток пуст, у них просто будет значение false, поэтому вы можете написать:

stringstream report_string;

foo(report_string)// some functions which may or may not write to report_string

string single_report;//string to read to

bool empty=true;//First assume it was empty
while(getline(report_string,single_report))//Alternatively use report_string>>single_report if you don't want entire lines
{
    empty=false;//...it wasn't empty
    bar(single_report);//Do whatever you want to do with each individual appended line 
}

if (empty)
{
    //... whatever you want to do if the stream was empty goes here
}

Следует отметить, что этот подход предполагает, что вы планировали ездить на велосипеде через струнный поток; если вы не были, то этот подход не может быть использован.