Hi,
I want to write a logging library and so im currently in the process of figuring out how best to go about it.
So far im imagining doing something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
class Logger : public std::stringstream
{
Logger()
~Logger() //writes stringstream::str() to each stream in m_streamRefs
staticvoid AddStream(std::ostream& stream); //adds stream to m_streamRefs
private:
static std::vector<std::reference_wrapper<std::ostream>> m_streamRefs;
};
//usage:
Logger::AddStream( std::cout );
Logger::AddStream( std::cerr );
Logger{} << "sfjsdlfjdslj\n";
//ideally i will have macros that can be turned on / off
DEBUG_LOG << "sdfjsldjf\n";
The thing is that i would like to keep it a header-only library (because i want to make logging macros that you can then turn on / off at compile time & not have to worry about telling your build system when / when not to link with the library).
The problem with this is that the m_streamRefs member need to be static and a static variable has to be initialized in a translation unit but since i want it to be a header-only library i dont have a translation unit to initialize it in.
And so when i compile it i get an undefined reference to m_streamRefs error.
Is there anything i can do about this? is there some way i can make the "includer" initialize the static variable (without having to manually type it) but at the same time avoid redefinition errors ?
Inline variables! You'll need a compiler with the appropriate C++17 support, but otherwise you can add the line inline std::vector<std::reference_wrapper<std::ostream>> Logger::m_streamRefs;
to your header. This will create multiple definitions across translation units, but they will all share the same address across those units. Neat, no?
Otherwise, if you can't use C++17, you can probably do something with an inline static member function that returns a reference to a (local) static variable.