I'm currently writing a class to wrap stringstream. My overall goal is to provide a threadsafe << (ostream) for my stringstream. I'm having trouble figuring out the correct syntax of what I'm trying to do. Any help would be most appreciative!
Below you'll find what I've tried. I know this is not the correct syntax, but it is kind of what I'm shooting for. I could of course not overload the << operator and force users to use the AddValue, but that wouldn't be ideal for quick and easy string manipulation while writing the code.
class WrappedStringStream
{
public :
WrappedStringStream() ;
template<typename T>
void AddValue( const T & value )
{
m_mutex.Lock() ;
//here I'd like to do something like m_stringstream << value, but of course since
//I'm overloading operator<< that won't work
m_mutex.Unlock() ;
}
friend std::ostream & operator<<( std::ostream & out, const WrappedStringStream & string )
{
string.AddValue( out ) ;
return out ;
}
protected :
std::stringstream m_stringstream ;
mutable Mutex m_mutex ;
}
As mentioned above it doesn't compile, which I understand since I'm passing WrappedStringStream as a const parameter and calling AddValue which isn't const - resulting in the discards qualifier error.
Here is the solution
#include <iostream>
#include <sstream>
#include <mutex>
using namespace std;
class MutexWrapper
{
private:
mutex& m_mutex;
public:
MutexWrapper(mutex& mtx) : m_mutex(mtx) { mtx.lock () ; };
~MutexWrapper() { m_mutex.unlock () ; };
};
class WrappedStringStream
{
public :
WrappedStringStream() { };
template<typename T>
std::ostream & operator<<(const T& value)
{
MutexWrapper wrapper(m_mutex);
return m_stringstream << value;
}
void showStream()
{
cout << m_stringstream.str();
}
protected :
stringstream m_stringstream;
mutable mutex m_mutex ;
};
int main()
{
WrappedStringStream ws;
ws << "This is a string, " << 5 << 6.78;
ws.showStream();
return 0;
}
Output
This is a string, 56.78
======== edit ==========
Originally I was not quiet understand what the questioner's final goal, but just focus on how to fix his syntax issue.It is not a good idea to use << in a multithreading environment. We have a Log class, and in our log class we only have a Log method which takes variable amount of parameters. That will solve the problem.
Still, there is a solution for using << to lock the thread, but really urgly and NOT recommend. Downside is obvious - if you forgot to add the 'LoggingStart' and 'LoggingEnd', you might caught deadlock.
Also thanks @RemyLebeau, It should return *this instead of m_stringstream.
Please see code below.
#include <iostream>
#include <sstream>
#include <mutex>
using namespace std;
class WrappedStringStream
{
public:
enum StreamSignals
{
LoggingStart,
LoggingEnd
};
WrappedStringStream() { };
std::ostream & operator<<(const StreamSignals& signal)
{
if (signal == LoggingStart)
m_mutex.lock();
else if (signal == LoggingEnd)
m_mutex.unlock();
return *this;
}
template<typename T>
std::ostream & operator<<(const T& value)
{
m_stringstream << value;
return *this;
}
void showStream()
{
cout << m_stringstream.str();
}
protected :
stringstream m_stringstream;
mutable mutex m_mutex ;
};
int main()
{
WrappedStringStream ws;
ws << WrappedStringStream::StreamSignals::LoggingStart;
ws << "This is a string, " << 5 << 6.78;
ws << WrappedStringStream::StreamSignals::LoggingEnd;
ws.showStream();
return 0;
}