Ввод и вывод информации — критически важная задача, без выполнения которой любая программа становится бесполезной. В C++ для решения данной задачи традиционно применяются потоки ввода-вывода, которые реализованы в стандартной библиотеке IOStream.
Плюсами такого подхода являются:
— универсальность: не важно, с чем связан поток, — ввод-вывод с консоли, файла, сокета, процесса происходит одинаково;
— прозрачность: программисту не нужно явно указывать тип вводимого или выводимого объекта;
— расширяемость: программист может добавить поддержку ввода-вывода в поток для любого своего объекта, просто перегрузив соответствующие операторы.
В библиотеке IOStream есть также класс
Он позволяет делать весьма забавные вещи, например, осуществлять преобразование типов:
Кроме того, этот класс можно использовать для форматирования сложных строк, например:
Понятно, что в данном случае использование
Получается, вам необходим промежуточный объект
C++ порой винят за его чрезмерную сложность и избыточность, которые, однако, в ряде случаев позволяют создавать весьма изящные конструкции. Вот и сейчас, шаблоны и возможность перегрузки операторов помогли мне создать обёртку над
А вот и сам
Работает это очень просто. С одной стороны, в классе
Быть может, кому-то эта обёртка окажется полезной. Буду рад услышать комментарии, предложения и пожелания.
Плюсами такого подхода являются:
— универсальность: не важно, с чем связан поток, — ввод-вывод с консоли, файла, сокета, процесса происходит одинаково;
— прозрачность: программисту не нужно явно указывать тип вводимого или выводимого объекта;
— расширяемость: программист может добавить поддержку ввода-вывода в поток для любого своего объекта, просто перегрузив соответствующие операторы.
В библиотеке IOStream есть также класс
stringstream, который позволяет связать поток ввода-вывода со строкой в памяти. Всё, что выводится в такой поток, добавляется в конец строки; всё, что считыватся из потока — извлекается из начала строки.Он позволяет делать весьма забавные вещи, например, осуществлять преобразование типов:
#include <sstream> #include <iostream> int main(int argc, char* argv[]) { std::stringstream ss; ss << "22"; int k = 0; ss >> k; std::cout << k << std::endl; return 0; }
Кроме того, этот класс можно использовать для форматирования сложных строк, например:
void func(int id, const std::string& data1, const std::string& data2) { std::stringstream ss; ss << "Operation with id = " << id << " failed, because data1 (" << data1 << ") is incompatible with data2 (" << data2 << ")"; std::cerr << ss.str(); }
Понятно, что в данном случае использование
stringstream излишне, так как сообщение можно было выводить напрямую в cerr. Но что если вы хотите вывести сообщение не в стандартный поток, а использовать, скажем, функцию syslog() для вывода сообщения в системный журнал? Или, скажем, сгенерировать исключение, содержащее данную строку как пояснение:void func(int id, const std::string& data1, const std::string& data2) { std::stringstream ss; ss << "Operation with id = " << id << " failed, because data1 (" << data1 << ") is incompatible with data2 (" << data2 << ")"; throw std::runtime_error(ss.str()); }
Получается, вам необходим промежуточный объект
stringstream, в котором вы сначала формируете строку, а затем получаете её с помощью метода str(). Согласитесь, громоздко?C++ порой винят за его чрезмерную сложность и избыточность, которые, однако, в ряде случаев позволяют создавать весьма изящные конструкции. Вот и сейчас, шаблоны и возможность перегрузки операторов помогли мне создать обёртку над
stringstream, которая позволяет форматировать строку в любом месте кода без дополнительных переменных как если бы я просто выводил данные в поток:void func(int id, const std::string& data1, const std::string& data2) { throw std::runtime_error(MakeString() << "Operation with id = " << id << " failed, because data1 (" << data1 << ") is incompatible with data2 (" << data2 << ")"); }
А вот и сам
MakeString:class MakeString { public: template<class T> MakeString& operator<< (const T& arg) { m_stream << arg; return *this; } operator std::string() const { return m_stream.str(); } protected: std::stringstream m_stream; };
Работает это очень просто. С одной стороны, в классе
MakeString перегружен оператор вывода (<<), который принимает в качестве аргумента константную ссылку на объект любого типа, тут же выводит этот объект в свой внутренний stringstream и возвращает ссылку на себя. С другой стороны, перегружен оператор преобразования к строке, который возвращает строку, сформированную stringstream'ом.Быть может, кому-то эта обёртка окажется полезной. Буду рад услышать комментарии, предложения и пожелания.
