c ++ выполняет функцию каждый раз, когда в поток записывается

У меня есть простая программа с графическим интерфейсом, которая использует пользовательскиеstringstream перенаправить вывод из консоли в текстовое поле в графическом интерфейсе (при некоторых обстоятельствах). В настоящее время. окно перерисовывается всякий раз, когда я нажимаю ввод, но этоВозможно, что выходные данные могут быть сгенерированы в другое время. Есть ли способ зарегистрировать функцию сstringstream который выполняется каждый раз, когда

 Kylo10 окт. 2012 г., 21:25
Можно'Вы просто перегружаете этот оператор?
 Kylo10 окт. 2012 г., 21:32
Конечно. Вы'Я упоминал, что вы используете пользовательский поток строк. Думаю, Адам Розенфилд дал вам хороший ответ.
 ewok10 окт. 2012 г., 21:29
@ Кайло, у меня не былоЯ не думал об этом. Я'Я не уверен, что это сработает, так как я хочу, чтобы функция выполнялась только при записи ЭТОГО потока строк, а не в любой поток строк. это можно сделать?

Ответы на вопрос(3)

Решение Вопроса

std::ostringstream (или дажеstd::stringstream) для этого вообще! Вместо этого я бы создал свой собственный буфер потока, заботясь об отправке данных в графический интерфейс. То есть яперезаписатьstd::streambuf::overflow() а такжеstd::streambuf::sync() отправить текущие данные в графический интерфейс. Чтобы также убедиться, что любой вывод отправляется немедленно, яя создалstd::ostream иметьstd::ios_base::unitbuf задавать. На самом деле, отправка изменений в функцию довольно проста, т.е.Я буду реализовывать это:

#include <streambuf>
#include <ostream>
#include <functional>
#include <string>
#include <memory>
#include <iostream> // only for testing...

#if HAS_FUNCTION
typedef std::function<void(std::string)> function_type;
#else
class function_type
{
private:
    struct base {
        virtual ~base() {}
        virtual base* clone() const = 0;
        virtual void  call(std::string const&) = 0;
    };
    template <typename function="">
    struct concrete
        : base {
        Function d_function;
        concrete(Function function)
            : d_function(function) {
        }
        base* clone() const { return new concrete<function>(this->d_function); }
        void  call(std::string const& value) { this->d_function(value); }
    };
    std::auto_ptr<base> d_function;
public:
    template <typename function="">
    function_type(Function function)
        : d_function(new concrete<function>(function)) {
    }
    function_type(function_type const& other)
        : d_function(other.d_function->clone()) {
    }
    function_type& operator= (function_type other) {
        this->swap(other);
        return *this;
    }
    ~function_type() {}
    void swap(function_type& other) {
        std::swap(this->d_function, other.d_function);
    }
    void operator()(std::string const& value) {
        this->d_function->call(value);
    }
};
#endif

class functionbuf
    : public std::streambuf {
private:
    typedef std::streambuf::traits_type traits_type;
    function_type d_function;
    char          d_buffer[1024];
    int overflow(int c) {
        if (!traits_type::eq_int_type(c, traits_type::eof())) {
            *this->pptr() = traits_type::to_char_type(c);
            this->pbump(1);
        }
        return this->sync()? traits_type::not_eof(c): traits_type::eof();
    }
    int sync() {
        if (this->pbase() != this->pptr()) {
            this->d_function(std::string(this->pbase(), this->pptr()));
            this->setp(this->pbase(), this->epptr());
        }
        return 0;
    }
public:
    functionbuf(function_type const& function)
        : d_function(function) {
        this->setp(this->d_buffer, this->d_buffer + sizeof(this->d_buffer) - 1);
    }
};

class ofunctionstream
    : private virtual functionbuf
    , public std::ostream {
public:
    ofunctionstream(function_type const& function)
        : functionbuf(function)
        , std::ostream(static_cast<std::streambuf*>(this)) {
        this->flags(std::ios_base::unitbuf);
    }
};

void some_function(std::string const& value) {
    std::cout << "some_function(" << value << ")\n";
}

int main() {
    ofunctionstream out(&some_function);
    out << "hello" << ',' << " world: " << 42 << "\n";
    out << std::nounitbuf << "not" << " as " << "many" << " calls\n" << std::flush;
}
</std::streambuf*></function></typename></function></typename></void(std::string)></iostream></memory></string></functional></ostream></streambuf>

Большая часть кода выше на самом деле не связана с поставленной задачей: она реализует примитивную версиюstd::function в случае, если C ++ 2011 можетне будет использоваться.

Если вы нене так много звонков, вы можете отключитьstd::ios_base::unitbuf и отправил данные только после очистки потока, например, с помощьюstd::flush (да, я знаю оstd::endl но, к сожалению, это обычно неправильно, я настоятельно рекомендую избавиться от него и использоватьstd::flush где действительно подразумевается флеш).

 Dietmar Kühl10 окт. 2012 г., 23:00
Я обновил код для реализации простой версииstd::function непосредственно. Все, что вам нужно сделать, это собрать код и, если у вас есть компилятор C ++ 2011, определить макросHAS_FUNCTION (например, используя-DHAS_FUNCTION в командной строке).
 Dietmar Kühl10 окт. 2012 г., 22:43
Тот'На самом деле это не главная проблема: единственное использование C ++ 2011 - это использованиеstd::function, Одним из простых средств является использованиеboost::function вместо. Если это неВ качестве опции либо достаточно просто создать простой класс с той же логикой для одного аргумента (это становится болезненным, когда нужно больше аргументов).
 ewok10 окт. 2012 г., 22:51
Вы можете дать мне команду компиляции для этого? как связать библиотеки повышения?
 ewok10 окт. 2012 г., 22:38
Благодарю. Тем не менее, я должен был указать, что я не могу использовать c ++ 11. Машины, на которых это будет скомпилировано и запущено, не будут иметь этого.

treambuf представляют устройства ввода-вывода, и каждый из них заботится о различных проблемах, специфичных для такого типа устройств. Стандарт определяет streambuf для файлов и другой для строк. Сетевой доступ будет использовать другой, и вывод на GUI также должен быть представлен как другой тип устройства, если вы 'Вы собираетесь использовать потоки вообще.

Написание подходящего класса streambuf isn 'Это тривиально и кажется неясным, но есть ресурсы.Стандартная библиотека C ++ - учебное пособие и справочник имеет небольшой раздел по этому вопросу.Стандартные потоки IOS C ++ и локали: продвинутый программистРуководство и справочник предоставляет подробную информацию. Поиск поsubclassing basic_streambuf Также появятся некоторые бесплатные ресурсы онлайн.

 Dietmar Kühl10 окт. 2012 г., 22:12
Гектометр Я могу'Я не понимаю, почему люди думают, что написание потокового буфера совершенно неясно! Это класс, как и любой другой, и интерфейс неэто действительно так сложно. За исключением нескольких простых опечаток, мне удалось реализовать код всего за несколько минут! ;)

вы можете извлечь подкласс из stringstream и перегрузить его оператор вставки потока для генерации событий?

псевдокод:

class AlertingStream : public stringstream
{
    ostream& operator << (type)
    {
        for (each listener in listeners)
        {
            listener.notify();
        }
        perform insertion;
        return *this;
    }
}

Ваш ответ на вопрос