Superclass for ostream and fstream - c++

I'm trying to make my own logging class in C++ using a wrapper class in which i overloaded operator<< that sends it to the cout. Now I want to change it, so that when i create instance of that class, i can pass and argument that logs data in std::cout or some file i create. What is the exact type that is superclass of both fstream and ostream? I tried with std::ios&, std::basic_ios&, std::basic_ostream& and none of them seems to work (throwing me compilation error).
class myostream {
public:
static int getlogLevel() {
return loglevel;
}
static void setlogLevel(int i) {
loglevel = i;
}
myostream(std::basic_ios& cout, int level)
: _cout(cout), _level(level)
{}
template<class T>
std::ostream& operator<<(T t) {
if(_level >= loglevel) {
_cout << loglevelcolor[_level] << loglevelname[_level] << " " << t << COL_RESET << std::endl;
}
return _cout;
}
private:
static int loglevel;
std::basic_ostream& _cout;
int _level;
};

Use base class std::ostream which is typedef for basic_ostream<char>, reference: iostream hierarchy.
Works for me (std::cout, std::ofstream):
#include <iostream>
class myostream {
public:
myostream(std::ostream& out)
: _out(out) {}
template<class T>
std::ostream& operator<<(T t) {
_out << "test" << " " << t << '\n' << 42 << std::endl;
return _out;
}
private:
std::ostream& _out;
};

What is the exact type that is superclass of both fstream and ostream?
It is std::ostream, which is an alias to std::basic_ostream<char>. See the class diagram for std::fstream.
Example:
class myostream {
public:
myostream(int level) // Log into stdout.
: _cout(std::cout), _level(level)
{}
myostream(char const* filename, int level) // Log into a file.
: _file(filename), _cout(_file), _level(level)
{
if(!_file.is_open())
throw std::runtime_error("Failed to open " + std::string(filename));
}
// ...
private:
std::ofstream _file;
std::ostream& _cout;
int _level;
};

Related

Autodeduction of return type

After reading C++ auto deduction of return type and C++ : Vector of template class, I'm still wondering how to do generic operations (e.g. operator << overload) on object. My code looks like
#include <map>
#include <memory>
#include <string>
#include <iostream>
/**
* Abstract placeholder for Cache polymorphism
*/
class ICache
{
public:
virtual void update() {};
friend std::ostream & operator << (std::ostream & out, const ICache & IC)
{
out << "you should never print this";
}
};
/**
* Concrete. Coupling a name with some cached value
*/
template<typename T>
class Cache :
public ICache
{
const std::string m_name;
T m_cached;
public:
Cache(const std::string & name) :
m_name(name),
m_cached(0)
{}
void update() override
{
// m_cached is synced with remote resource; action depends both from T and m_name
}
void set(const T t)
{
std::cout << m_name << " setting " << +m_cached << " -> " << +t << std::endl;
m_cached = t;
}
inline T get() const noexcept { return m_cached; }
friend std::ostream & operator << (std::ostream & out, const Cache & O)
{
out << "Cache<" << O.m_name << ", " << O.m_cached << ">";
}
};
class CacheMap
{
std::map<std::string, std::unique_ptr<ICache>> m_map;
template<typename T>
Cache<T>* _get_ptr(const std::string & name) const
{
return reinterpret_cast<Cache<T>*>(m_map.at(name).get());
}
public:
template<typename T>
T get(const std::string & name) const
{
return _get_ptr<T>(name)->get();
}
template <typename T>
void set(const std::string & name, T t)
{
_get_ptr<T>(name)->set(t);
}
template <typename T>
void insert(const std::string & name, T def = 0)
{
std::unique_ptr<ICache> up = std::make_unique<Cache<T>>(name);
m_map.insert({name, std::move(up)});
set<T>(name, def);
}
friend std::ostream & operator << (std::ostream & out, const CacheMap & OM)
{
out << "OM{";
for (const auto & IO : OM.m_map)
out << IO.first << ": " << *(IO.second.get()) << ", "; // ver1
// out << IO.first << ": " << (IO.second->get()) << ", "; // ver2
out << "}";
return out;
}
};
int main()
{
CacheMap m;
int i= 70000;
m.insert<int>("i", 69999);
m.insert<short>("s", 699);
m.insert<char>("c", 69);
m.set("i", i);
std::cout << m << std::endl;
}
Line marked with trailing //ver1 shows you should never print this which makes sense; I'm dealing with std::unique_ptr<ICache> objects.
Line marked with trailing //ver2 won't compile at all, and this makes sense too.
What I'd like to do inside CacheMap is to auto-detect, at runtime (hmm sounds bad) the correct T, given a map key, in order to fire the right reinterpret_cast<> and to retrieve m_cached value.
EDIT 1
If compiling with g++ -O3, ver1 line causes a segmentation violation.
Just use a virtual function. The time you cast your variable from Cache<int> pointer type to ICache pointer you lose compile time information about it. That information is lost. You can use dynamic_cast in your friend ICache::operator<< to handle all the different types... To properly resolve type information use virtual functions - ie. unique data tied to each of the class.
#include <map>
#include <memory>
#include <string>
#include <iostream>
class ICache
{
public:
virtual ~ICache() {};
virtual void update() {};
// -------- HERE --------------
virtual std::ostream& printme(std::ostream & out) const = 0;
friend std::ostream& operator << (std::ostream & out, const ICache & IC) {
return IC.printme(out);
}
};
template<typename T>
class Cache : public ICache {
const std::string m_name;
T m_cached;
public:
Cache(const std::string & name): m_name(name), m_cached(0) {}
void update() override {}
void set(const T t) {
std::cout << m_name << " setting " << +m_cached << " -> " << +t << std::endl;
m_cached = t;
}
inline T get() const noexcept { return m_cached; }
std::ostream& printme(std::ostream & out) const override {
out << "Cache<" << m_name << ", " << m_cached << ">";
return out;
}
};
class CacheMap {
std::map<std::string, std::unique_ptr<ICache>> m_map;
template<typename T>
Cache<T>* _get_ptr(const std::string & name) const {
return dynamic_cast<Cache<T>*>(m_map.at(name).get());
}
public:
template<typename T>
T get(const std::string & name) const {
return _get_ptr<T>(name)->get();
}
template <typename T>
void set(const std::string & name, T t) {
_get_ptr<T>(name)->set(t);
}
template <typename T>
void insert(const std::string & name, T def = 0) {
std::unique_ptr<ICache> up = std::make_unique<Cache<T>>(name);
m_map.insert({name, std::move(up)});
set<T>(name, def);
}
friend std::ostream& operator << (std::ostream & out, const CacheMap & OM) {
out << "OM{";
for (const auto & IO : OM.m_map)
out << IO.first << ": " << *(IO.second.get()) << ", "; // ver1
// out << IO.first << ": " << (IO.second->get()) << ", "; // ver2
out << "}";
return out;
}
};
int main()
{
CacheMap m;
int i= 70000;
m.insert<int>("i", 69999);
m.insert<short>("s", 699);
m.insert<char>("c", 69);
m.set("i", i);
std::cout << m << std::endl;
}
will output on godbolt:
i setting 0 -> 69999
s setting 0 -> 699
c setting 0 -> 69
i setting 69999 -> 70000
OM{c: Cache<c, E>, i: Cache<i, 70000>, s: Cache<s, 699>, }
I just spotted, to protect against very bad and hard to debug errors, I remind you to use dynamic_cast instead of reintepret_cast in CacheMap::_get_ptr().
There are various ways, but generally I would implement a single operator<<() that calls a virtual function.
class ICache {
protected: // so the function is only accessible to derived classes
virtual std::ostream print(std::ostream &out) const = 0; // force derived classes to override
friend std::ostream &operator<<(std::ostream &out, const ICache& c);
};
Then place a single definition of the operator<< in a single compilation unit
// definition of class ICache needs to be visible here
std::ostream &operator<<(std::ostream &out, const ICache& c)
{
return c.print(out);
}
And to implement the derived class
// definition of ICache here
template<class T>
class Cache: ICache
{
protected:
std::ostream print(std::ostream &out) const override
{
// output a Cache<T>
return out;
}
};
The advantage of this is that each class takes responsibility for outputting itself, rather than a container class having to work out which output function to call (and the opportunity for a programmer to forget to do that).
First, reinterpret_cast is a dangerous thing. In contexts of polymorphism you mostly want to use dynamic_cast.
You problem is not about templates etc at all, but it is more about that you want to make the operator<< virtual, which is not possible, since it is a friend function. An easy workaround is the following:
class ICache {
virtual void print(std::ostream &out) const { // Prefer pure virtual
out << "Never print this\n";
}
friend std::ostream &operator<<(std::ostream &out, const ICache& c) {
c.print(out);
return out;
}
};
template<class T>
class Cache: ICache {
void print(std::ostream &out) const override {
out << "Print this instead\n";
}
};
will do what you want without any casting.

Automatic template type deduction confusing pointers and references

Whilst trying to debug some code, I created a class to dump the values of a complicated hierarchy of objects to a text file so that I can compare a case where it works against a case where it doesn't. I implemented the class like this (reduced to a bare example):
#include <iostream>
class someOtherClass
{
public:
someOtherClass()
: a(0)
, b(1.0f)
, c(2.0)
{}
int a;
float b;
double c;
};
class logger
{
public:
// Specific case for handling a complex object
logger& operator << ( const someOtherClass& rObject )
{
std::cout << rObject.a << std::endl;
std::cout << rObject.b << std::endl;
std::cout << rObject.c << std::endl;
return *this;
}
// [other class specific implementations]
// Template for handling pointers which might be null
template< typename _T >
logger& operator << ( const _T* pBar )
{
if ( pBar )
{
std::cout << "Pointer handled:" << std::endl;
return *this << *pBar;
}
else
std::cout << "null" << std::endl;
return *this;
}
// Template for handling simple types.
template< typename _T >
logger& operator << ( const _T& rBar )
{
std::cout << "Reference: " << rBar << std::endl;
return *this;
}
};
int main(int argc, char* argv[])
{
logger l;
someOtherClass soc;
someOtherClass* pSoc = &soc;
l << soc;
l << pSoc;
pSoc = nullptr;
l << pSoc;
return 0;
}
I was expecting to get the following output:
0
1
2
Pointer handled:
0
1
2
null
But what I actually get is:
0
1
2
Reference: 010AF7E4
Reference: 00000000
The automatic type deduction appears to be picking the reference implementation and setting the type to someOtherClass* rather than picking the pointer implementation. I'm using Visual Studio 2012.
In logger& operator << ( const _T& rBar ) type T can be a pointer type, so in order to work properly this template needs some restriction:
template< typename _T , typename = typename ::std::enable_if_t<!std::is_pointer<_T>::value> >
logger& operator << ( const _T& rBar )
{
std::cout << "Reference: " << rBar << std::endl;
return *this;
}
Online compiler
This is required because when templates are instantiated the const _T & pBar with _T = someOtherClass * variant will be proffered as conversion sequence required in this case will only include a reference binding which is considered an identity conversion while const _T* pBar variant with _T = someOtherClass will involve a copy-initialization.
Here are a few modifications and annotations which may help as this logging class grows and becomes more mature.
I have attempted to:
a) solve the initial problem of incorrect type deduction.
b) decouple the logger from the things being logged (otherwise your logger has to know about the entire application and all libraries).
c) provide a mechanism for easily allowing logging of any type, even if provided by a third-party library.
#include <iostream>
// I've put the logger and its helpers into a namespace. This will keep code tidy and help with
// ADL.
namespace logging
{
// define a general function which writes a value to a stream in "log format".
// you can specialise this for specific types in std:: if you wish here
template<class T>
void to_log(std::ostream& os, T const& value)
{
os << value;
}
// define a general function objects for writing a log-representation of tyoe T.
// There are 2 ways to customise this.
// a) provide a free function called to_log in the same namespace as your classes (preferred)
// b) specialise this class.
template<class T>
struct log_operation
{
void operator()(std::ostream& os, T const& value) const
{
to_log(os, value);
}
};
// specialise for any pointer
template<class T>
struct log_operation<T*>
{
void operator()(std::ostream& os, T* ptr) const
{
if (!ptr)
os << "null";
else
{
os << "->";
auto op = log_operation<std::decay_t<T>>();
op(os, *ptr);
}
}
};
// the logger is now written in terms of log_operation()
// it knows nothing of your application's types
class logger
{
public:
// Template for handling any type.
// not that this will also catch pointers.
// we will disambiguate in the log_operation
template< typename T >
logger& operator << ( const T& rBar )
{
auto op = log_operation<std::decay_t<T>>();
op(std::cout, rBar);
std::cout << std::endl;
return *this;
}
};
}
class someOtherClass
{
public:
someOtherClass()
: a(0)
, b(1.0f)
, c(2.0)
{}
int a;
float b;
double c;
};
// someOtherClass's maintainer provides a to_log function
void to_log(std::ostream& os, someOtherClass const& c)
{
os << "someOtherClass { " << c.a << ", " << c.b << ", " << c.c << " }";
}
namespace third_party
{
// the is in a 3rd party library. There is no to_log function and we can't write one which will be found with
// ADL...
struct classWhichKnowsNothingOfLogs {};
}
/// ..so we'll specialise in the logging namespace
namespace logging
{
template<>
struct log_operation<::third_party::classWhichKnowsNothingOfLogs>
{
void operator()(std::ostream& os, ::third_party::classWhichKnowsNothingOfLogs const& value) const
{
os << "classWhichKnowsNothingOfLogs {}";
}
};
}
int main(int argc, char* argv[])
{
logging::logger l;
someOtherClass soc;
someOtherClass* pSoc = &soc;
l << soc;
l << pSoc;
pSoc = nullptr;
l << pSoc;
l << third_party::classWhichKnowsNothingOfLogs();
return 0;
}
expected output:
someOtherClass { 0, 1, 2 }
->someOtherClass { 0, 1, 2 }
null
classWhichKnowsNothingOfLogs {}

Overload function on parent and child - how to access the parent function

Here is what I would like to do:
class Msg {
int target;
public:
Msg(int target): target(target) { }
virtual ~Msg () { }
virtual MsgType GetType()=0;
};
inline std::ostream& operator <<(std::ostream& ss,Msg const& in) {
return ss << "Target " << in.target;
}
class Greeting : public Msg {
std::string text;
public:
Greeting(int target,std::string const& text) : Msg(target),text(text);
MsgType GetType() { return TypeGreeting; }
};
inline std::ostream& operator <<(std::ostream& ss,Greeting const& in) {
return ss << (Msg)in << " Text " << in.text;
}
Unfortunately, this doesn't work as the cast to Msg on the second last line fails as Msg is abstract. I would however like to have the code to output the information for the parent in only one place. What is the correct way to do this? Thanks!
EDIT: Sorry, just to be clear, it is this line return ss << (Msg)in << " Text " << in.text; I don't know how to write.
Try ss<<(Msg const&)in.
And probably you have to make operator a friend of Greeting class.
#include "iostream"
#include "string"
typedef enum { TypeGreeting} MsgType;
class Msg {
friend inline std::ostream& operator <<(std::ostream& ss,Msg const& in);
int target;
public:
Msg(int target): target(target) { }
virtual ~Msg () { };
virtual MsgType GetType()=0;
};
inline std::ostream& operator <<(std::ostream& ss,Msg const& in) {
return ss << "Target " << in.target;
}
class Greeting : public Msg {
friend inline std::ostream& operator <<(std::ostream& ss,Greeting const& in);
std::string text;
public:
Greeting(int target,std::string const& text) : Msg(target),text(text) {};
MsgType GetType() { return TypeGreeting; }
};
inline std::ostream& operator <<(std::ostream& ss,Greeting const& in) {
return ss << (Msg const&)in << " Text " << in.text;
}
int _tmain(int argc, _TCHAR* argv[])
{
Greeting grt(1,"HELLZ");
std::cout << grt << std::endl;
return 0;
}
Not great design, but solves your problem.

Why does writing to temporary stream fail?

Consider the following code:
#include <sstream>
#include <iostream>
class Foo : public std::stringstream {
public:
~Foo() { std::cout << str(); }
};
int main()
{
Foo foo;
foo << "Test1" << std::endl;
Foo() << "Test2" << std::endl;
return 0;
}
When I execute this, it gives me:
004177FC
Test1
I do not understand why the second example gives me gibberish. The temporary should live until the entire expression is evaluated, so why does it not behave the same as the first example?
I tested it.
I can guess that operator<< cannot bind a temporary to a non-const reference, so any externally defined operator<< functions will not work on the Foo temporary, but any class member ones will so if ostream or ostringstream has any internal operator<< members they will work.
Therefore it may be that the overload to a pointer is a member function whilst the special one for const char * is externally declared.
The non-temporary can bind to the non-const reference for the more specialist overload.
If you really need this you can workaround with a wrapper
class Foo :
{
mutable std::ostringstream oss;
public:
~Foo()
{
std::cout << oss.str();
}
template<typename T>
std::ostream&
operator<<( const T& t ) const
{
return oss << t;
}
};
Tested and works. The first operator<< will return you the underlying stream.
I tried this too but it coredumped:
class Foo : std::ostringstream
{
Foo & nonconstref;
public:
Foo() : nonconstref( *this ) {}
~Foo()
{
std::cout << str();
}
template<typename T>
std::ostream&
operator<<( const T& t ) const
{
return nonconstref << t;
}
};
This also works:
class Foo : public std::ostringstream
{
public:
Foo() {}
~Foo()
{
std::cout << str();
}
Foo& ncref()
{
return *this;
}
};
int main()
{
Foo foo;
foo << "Test1" << std::endl;
Foo().ncref() << "Test2" << std::endl;
}

Have a C++ Class act like a custom ostream, sstream

I have a C++ class MyObject and I want to be able to feed this data like I would to a osstream (but unlike a direct sstream, have the incoming data be formatted a special way). I can't seem to figure out how to overload a operator for MyObject to eat input given to it.
class MyObject {
public:
ostringstream s;
FEEDME
};
int main() {
MyObject obj;
obj.FEEDME << "Hello" << 12345;
// I want obj.s == ":Hello::12345:"
}
I want it so every item fed in be surrounded by : :
So in the given example, s = ":Hello::12345" should be the final outcome. What my question is, how can I tell the object that when ever a <<something, put : : around the something.
Is this possible?
try this:
class MyObject {
public:
template <class T>
MyObject &operator<<(const T &x) {
s << ':' << x << ':';
return *this;
}
std::string to_string() const { return s.str(); }
private:
std::ostringstream s;
};
MyObject obj;
obj << "Hello" << 12345;
std::cout << obj.to_string() << std::endl;
There are certain things you won't be able to shove into the stream, but it should work for all the basics.
You may find the answers for How do I create my own ostream/streambuf? helpful.
I would take a slightly different approach and create a formater object.
The formater object would then handle the inserting of format character when it is applied to a stream.
#include <iostream>
template<typename T>
class Format
{
public:
Format(T const& d):m_data(d) {}
private:
template<typename Y>
friend std::ostream& operator<<(std::ostream& str,Format<Y> const& data);
T const& m_data;
};
template<typename T>
Format<T> make_Format(T const& data) {return Format<T>(data);}
template<typename T>
std::ostream& operator<<(std::ostream& str,Format<T> const& data)
{
str << ":" << data.m_data << ":";
}
int main()
{
std::cout << make_Format("Hello") << make_Format(123);
}