#include <sstream> class bostringstream { public: bostringstream() : oss() {} template <typename T, typename std::enable_if<std::is_fundamental<T>::value, bool>::type = true> bostringstream& operator<<(const T& v) { oss.write((char*)&v, sizeof(T)); return *this; } template <typename T, typename std::enable_if< std::is_fundamental<typename T::value_type>::value, bool>::type = true> bostringstream& operator<<(const T& v) { oss.write((char*)v.data(), v.size() * sizeof(typename T::value_type)); return *this; } template <typename _InputIterator> bostringstream& write(_InputIterator first, _InputIterator last) { char* data = (char*)&(*first); auto n = std::distance(first, last); oss.write(data, n * sizeof(*first)); return *this; } template <typename T, typename std::enable_if<std::is_fundamental<T>::value, bool>::type = true> bostringstream& write(const T* v, std::streamsize count) { oss.write((char*)v, sizeof(T) * count); return *this; } auto rdbuf() const { return oss.rdbuf(); } auto str() const { return oss.str(); } std::size_t size() { return oss.tellp(); } protected: std::ostringstream oss; };
Example:
#include <array> #include <string> #include <vector> #include <iostream> #include <fstream> #include "bsstream.hpp" int main(int argc, char **argv) { int i = 1; float j = 1.1; double k = 1.2; std::vector<int> ii{1,2}; std::vector<double> jj{1.2,2.2}; std::string kk = "abcd"; std::array<int, 2> ll{3,4}; int l[] = {1,2}; bostringstream of; of << i << j <<k; of <<ii << jj << kk << ll; of.write(l, 2); std::ofstream oof("foo.bin", std::ios::binary); oof << of.str(); oof.close(); }
Not an elegant solution but works and is flexible
Edit:
- Nov 12th, 2023: I have used similar code in my project for a while. Instead of using a std::ostringstream as a class member, I pass a pointer to type std::ostream to the class and do the writing part. It in general works fine.