I am trying to create a Log class for my project at school. It needs to either be able to write information to the stdout or to a file depending on the parameters it is passed. I was looking into how to do this and I stumbled upon a thread with a similar question here: Obtain a std::ostream either from std::cout or std::ofstream(file)
The only difference between this thread and my own is that I want to do it inside of a class. Looking at the solution though they use std::ostream out(buf) and construct the ostream on the fly with buf. How can i declare this properly in my Log class to be able to construct the "out" object only once i enter my Log constructor?
I took a quick stab at it below but I am not sure if it is correct or if I am on the right track. Appreciate any help, thanks.
EDIT: I want to be able to do out << "Some string" << endl; after i get this Log class working properly.
EDIT2: An error I am now receiving with the new code below error : 'std::basic_ostream<_CharT, _Traits>::basic_ostream() [with _CharT = char, _Traits = std::char_traits<char>]' is protected
// log.h
#include <string>
#include <fstream>
#ifndef LOG_H_
#define LOG_H_
class Log
{
public:
enum Mode { STDOUT, FILE };
// Needed by default
Log(const char *file = NULL);
~Log();
// Writing methods
void write(char *);
void write(std::string);
private:
Mode mode;
std::streambuf *buf;
std::ofstream of;
std::ostream out;
};
#endif
// log.cpp
#include "log.h"
#include <iostream>
#include <stdlib.h>
#include <time.h>
Log::Log(const char *file)
{
if (file != NULL)
{
of.open(file);
buf = of.rdbuf();
mode = FILE;
}
else
{
buf = std::cout.rdbuf();
mode = STDOUT;
}
// Attach to out
out.rdbuf(buf);
}
Log::~Log()
{
if (mode == FILE)
of.close();
}
void Log::write(std::string s)
{
out << s << std::endl;
}
void Log::write(char *s)
{
out << s << std::endl;
}
You create tmp with std::ostream tmp(buf); and store the address of it in out with this->out = &tmp;. However, tmp will go out of scope at the end of the constructor and the pointer will no longer be pointing at a valid object.
What you should do instead is make out not a std::ostream* but simply a std::ostream:
std::ostream out;
Then in your constructor, once you've got the buf ready, you can give it to out by doing out.rdbuf(buf);.
Response to edit:
The std::ostream doesn't have a default constructor - it has to take a buffer pointer. My mistake. However, the fix is simple. Use your constructor's member initialization list to pass a null pointer (nullptr in C++11, 0 or NULL in C++03):
Log::Log(const char *file)
: out(nullptr)
{
// ...
}
Related
This is a very strange issue. I have two classes: a custom console class (CConsole) and a test class (CHashTableTest) which I've made to play around with maps and unordered_maps to learn how they work.
In my console class I have a public static member variable of CConsole that exposes a static console object to the rest of the project so that I can write to this console when ever I want. This works fine for all of my classes including the test class but only when that test classes uses map and not unordered_map!
The error that I receive is:
error LNK2001: unresolved external symbol "public static class CConsole CConsole:output" (?output#CConsole##2V1#A)
It comes from the class that calls the methods on the test class and not the test class itself but nothing strange is happening in the calling class, it simply instantiates the CHashTableTest object (passing in a CConsole object) and calls Add and Get on it. It is placed in a separate project but this isn't a problem when I use map as the static member variable has been made external using _declspec(ddlexport).
The solution is setup in Visual Studio 2012, the CConsole and CHashTableTest classes are in a DLL project which is an external reference of a Unit Test project where the calling code exists.
The CConsole and CHashTableTest files:
Console.h
#ifndef _CONSOLE_H_
#define _CONSOLE_H_
#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <time.h>
// Defines a set of output modes for the CConsole class. This will affect what output the console will target.
// The default is COUT.
enum _declspec(dllexport) EConsoleMode
{
// Output sent to a CConsole object will be printed using cout.
COUT,
// Output sent to a CConsole object will be printed to a file.
OUTPUT_FILE,
// Output sent to a CConsole object will be printed using OutputDebugString.
OUTPUT_DEBUG_STRING,
// Output sent to a CConsole object will be printed using Debug::WriteLine.
DEBUG_WRITE_LINE,
// Output sent to a CConsole object will be printed using Console::WriteLine.
CONSOLE_WRITE_LINE,
// Output sent to a CConsole object will not be printed.
NO_OUTPUT,
};
// An output wrapper class that allows logging and redirecting of log and debugging messages to different
// output targets.
class _declspec(dllexport) CConsole
{
public:
static CConsole output;
// Constructs a CConsole object with a specific console mode, default is COUT.
CConsole(EConsoleMode mode = COUT, const char* filePath = "C:/output.txt");
~CConsole(void);
// Gets the mode of this CConsole object.
EConsoleMode GetMode();
const char* GetFilePath();
// Sets the output file path of this CConsole object.
void SetFilePath(const char* filePath);
void TimeStamp();
// Logs a message with this specific CConsole object. An indirect call to an operator overload of
// CConsole << Type
template <typename T> void Log(const T &message);
protected:
// The mode of this CConsole object.
EConsoleMode m_mode;
// The file path of the output file for this CConsole object.
const char* m_filePath;
};
// Operator overload of CConsole << Type, queries the mode of the given CConsole object and
// selects the appropriate output method associated with the mode.
template <typename T>
CConsole operator<< (CConsole console, const T &input)
{
switch(console.GetMode())
{
case COUT:
{
std::cout << input << "\n";
break;
}
case OUTPUT_FILE:
{
ofstream fout;
fout.open (console.GetFilePath(), ios::app);
fout << input;
fout.close();
break;
}
#if ON_WINDOWS
case OUTPUT_DEBUG_STRING:
{
OutputDebugString(input);
break;
}
case DEBUG_WRITE_LINE:
{
Debug::WriteLine(input);
break;
}
case CONSOLE_WRITE_LINE:
{
Console::WriteLine(input);
break;
}
#endif
case NO_OUTPUT:
{
break;
}
default:
{
std::cout << input;
break;
}
}
return console;
}
// Logs a message by calling the operator overload of << on this CConsole object with the message
// parameter.
template <typename T>
void CConsole::Log(const T &message)
{
this << message;
}
#endif
Console.cpp
#include "Console.h"
CConsole CConsole::output = *new CConsole(OUTPUT_FILE, "C:/LocalProjects/---/output.txt"); // Known memory leak here, discussed in comments
// Constructs a CConsole object by assigning the mode parameter to the
// m_mode member variable.
CConsole::CConsole(EConsoleMode mode, const char* filePath)
{
m_mode = mode;
m_filePath = filePath;
TimeStamp();
}
CConsole::~CConsole(void)
{
//Log("\n\n");
}
// Returns the current mode of this CConsole object.
EConsoleMode CConsole::GetMode()
{
return m_mode;
}
const char* CConsole::GetFilePath()
{
return m_filePath;
}
void CConsole::TimeStamp()
{
if(m_mode == OUTPUT_FILE)
{
std::ofstream file;
file.open (m_filePath, std::ios::app); //
std::time_t currentTime = time(nullptr);
file << "Console started: " << std::asctime(std::localtime(¤tTime));
file.close();
}
}
void CConsole::SetFilePath(const char* filePath)
{
m_filePath = filePath;
}
HashTableTest.h
#ifndef _HASH_TABLE_TEST_H_
#define _HASH_TABLE_TEST_H_
#include <unordered_map>
#include <map>
#include <vector>
#include "Debuggable.h"
#include "Console.h"
using namespace std;
//template class __declspec(dllexport) unordered_map<int, double>;
struct Hasher
{
public:
size_t operator() (vector<int> const& key) const
{
return key[0];
}
};
struct EqualFn
{
public:
bool operator() (vector<int> const& t1, vector<int> const& t2) const
{
CConsole::output << "\t\tAdding, t1: " << t1[0] << ", t2: " << t2[0] << "\n"; // If I delete this line then no error!
return (t1[0] == t2[0]);
}
};
class __declspec(dllexport) CHashTableTest : public CDebuggable
{
public:
CHashTableTest(CConsole console = *new CConsole());
~CHashTableTest(void);
void Add(vector<int> key, bool value);
bool Get(vector<int> key);
private:
CConsole m_console;
unordered_map<vector<int>, bool, Hasher, EqualFn> m_table; // If I change this to a map then no error!
};
#endif
Just to be clear, if I change 'unordered_map' above to 'map' and remove the Hasher function object from the template argument list this will compile. If I don't I get the linker error. I haven't included HashTableTest.cpp because it contains practically nothing.
EDIT
I'm not sure if I'm using unordered_map properly here is the implementation for the CHashTableTest class:
HashTableTest.cpp
#include "HashTableTest.h"
CHashTableTest::CHashTableTest(CConsole console) : CDebuggable(console)
{
}
CHashTableTest::~CHashTableTest(void)
{
}
void CHashTableTest::Add(vector<int> key, bool value)
{
m_table[key] = value;
}
bool CHashTableTest::Get(vector<int> key)
{
return m_table[key];
}
When a DLL's generated import library is being linked with an consuming EXE (or another DLL) the declspecs of the items being brought in should be declspec(dllimport) on the receiver-side. When you're building the actual DLL those same items are made available by usage of declspec(dllexport). Your code has the latter, but not the former.
This is normally achieved by a single preprocessor macro that is defined only for your DLL project in the preprocessor section of the compiler configuration. For example in your header(s) that are declaring things exported from your DLL:
#ifndef MYDLL_HEADER_H
#ifdef MYDLL_EXPORTS
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
class EXPORT CConsole
{
// stuff here.
};
#endif
Doing this will tell the compiler when building the DLL to export the class members, including class statics, because MYDLL_EXPORTS is defined in the preprocessor configuration flags for your DLL project.
When building a consuming project, do NOT define MYDLL_EXPORTSin the preprocessor configuration of the compiler settings. It will thusly use dllimport, rather than dllexport. That should square away the linker to know where to look for the things it needs.
Best of luck.
I have a function
foo(ostream& os)
which writes to the ostream passed to it.
I now want to write a test and therefore would like to store whatever is written by foo into a list.
What is a clean way of doing this?
Populate the list with a std::ostringstream instance:
#include <sstream>
#include <cassert>
void foo(std::ostream& out) { out << "test1"; } // example implementation
void test_foo()
{
std::ostringstream buffer;
foo(buffer);
assert(buffer.str() == "test1");
}
I want to use file streams and consol output stream. In constructor, I want to initialize with either file or consol output stream depending on parameter passed to constructor. Then I will have another function in class which will redirect output to that stream. what will be the code for it? I am trying with the below code which is not working.
Any other design suggestions are welcome.
class Test
{
private:
std::ios *obj;
std::ofstream file;
std::ostream cout1;
public:
// Test(){}
Test(char choice[])
{
if(choice=="file")
{
obj=new ofstream();
obj->open("temp.txt");
}
else
obj=new ostream();
}
void printarray()
{
for(int i=0;i<5;i++)
(*obj)<<"\n \n"<<"HI"
}
};
Something like this should work:
#include <iostream>
#include <fstream>
#include <string>
class Test
{
private:
std::ofstream file;
std::ostream& obj;
public:
// Use overloaded constructors. When the default constructor is used,
// use std::cout. When the constructor with string is used, use the argument
// as the file to write to.
Test() : obj(std::cout) {}
Test(std::string const& f) : file(f.c_str()), obj(file) {}
void printarray()
{
for(int i=0;i<5;i++)
obj<<"\n " << "HI" << " \n";
}
};
int main()
{
Test a;
a.printarray();
Test b("out.txt");
b.printarray();
}
PS Look at the changes to printarray. What you were trying, with %s, is good for the printf family of functions but not for std::ostream.
Any other design suggestions are welcome.
Two of these members are useless:
std::ios *obj;
std::ofstream file;
std::ostream cout1;
You can't do anything with a std::ios, a std::ostream that isn't associated with a streambuf is useless, and you never use file or cout1 anyway!
You want:
std::ofstream file;
std::ostream& out;
as shown in R Sahu's answer, and write to out.
Test(char choice[])
{
if(choice=="file")
This doesn't work, you need to use strcmp to compare char strings. You should probably use std::string not char*.
So here's an interesting question, How would I make something kinda like a wrapper for cout?
I want to be able to add it into a dll so I can throw it into my programs. but the basic syntax of it should be
Mything::mesage << "I'm some text" << im_an_int << someclass << mything::endl;
or
Mything::mesageandlog << "I'm going to print to console, and to a file!" << mything::endl;
I can handle most of the internal logic but as to what I should put to even do this. kinda stumped.
Possibly make a static stream member in my class called message, then have an event fire when its written too that runs it through a method?
Idk, I looked around and found something sortA similar, but as for throwing it into a dll I'm at a loss. (How to write a function wrapper for cout that allows for expressive syntax?)
because this requires me to use extern and a variable, but how would I make it static so I can just straight call it without creating a variable?
Bit of clarification, something like this:
mydll.h
#include <iostream>
namespace mynamespace {
extern struct LogMessage{};
template <typename T>
LogMessage& operator<< (LogMessage &s, const T &x) {
SetStdHandle(STD_OUTPUT_HANDLE, GetStdHandle(STD_OUTPUT_HANDLE));
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE);
std::cout << "[IF] ";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_WHITE);
//LogTimestamp(); --ill impliment this.
std::cout << x << endl;
//writeStreamToLogfile(s); --and ill handle this.
return s;
}
}
driverprogram.h
#include <mydll.h>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
mynamespace::LogMessage << "Something: << std::endl;
}
expected output:
"[IF] [00:00:00] Something
You can create a struct, that has a << operator
struct OutputThing
{
template< class T >
OutputThing &operator<<( T val )
{
std::cout<<val;
return *this;
}
};
Now whenever you want to log, you will have to instance the object.
OutputThing()<<"x ="<<x;
If you want to avoid the repeated construction and destruction of the object, you can make it a singleton.
struct OutputThingSingleton
{
static OutputThingSingleton& GetThing()
{
static OutputThingSingleton OutputThing;
return OutputThing;
}
template< class T >
OutputThingSingleton &operator<<( T val )
{
std::cout<<val;
return *this;
}
private:
OutputThingSingleton()
{};
};
So the call now looks like
OutputThingSingleton::GetThing()<<"x ="<<x;
Which you could shorten using a macro.
This will work across multiple dlls, however depending on how it is used you can have multiple instances of the singleton existing. This would work fine as long as you don't want to maintain any state in your singleton. If you do need to ensure a single instance, you can compile it in its own dll. Any other binary that uses this dll will share the single instance 'owned' by the dll.
First of all, just to give fair warning, I'm pretty sure this won't work in a DLL. You want to put it into a header (as it's shown here).
Second, it's probably a little more elaborate than you were considering. In particular, it defines a multi-output stream class that works like any other stream. Essentially any normal overload of operator<< should work fine with it.
Unlike a normal stream operator, however, the output goes to multiple streams, and each line of output (on all the streams) is preceded by a prefix (currently set to the value "[FIX]", but it just uses the content of a string, so whatever you put in that string should work. A more polished/finished implementation would probably allow you to set the prefix with something like a manipulator, but this (currently) doesn't support that.
Finally, it does some variadic template trickery, so you can specify the output files as either file names or existing ostream objects, or a combination thereof (e.g., see demo main at end).
First, the header:
#ifndef LOGGER_H_INC_
#define LOGGER_H_INC_
#include <iostream>
#include <streambuf>
#include <vector>
#include <fstream>
class logger: public std::streambuf {
public:
logger(std::streambuf* s): sbuf(s) {}
~logger() { overflow('\n'); }
private:
typedef std::basic_string<char_type> string;
int_type overflow(int_type c) {
if (traits_type::eq_int_type(traits_type::eof(), c))
return traits_type::not_eof(c);
switch (c) {
case '\n':
case '\r': {
prefix = "[FIX]";
buffer += c;
if (buffer.size() > 1)
sbuf->sputn(prefix.c_str(), prefix.size());
int_type rc = sbuf->sputn(buffer.c_str(), buffer.size());
buffer.clear();
return rc;
}
default:
buffer += c;
return c;
}
}
std::string prefix;
std::streambuf* sbuf;
string buffer;
};
namespace multi {
class buf : public std::streambuf {
std::vector<std::streambuf *> buffers;
public:
typedef std::char_traits<char> traits_type;
typedef traits_type::int_type int_type;
buf() {}
void attach(std::streambuf *s) { buffers.push_back(s); }
void attach(std::ofstream &s) { buffers.push_back(s.rdbuf()); }
int_type overflow(int_type c) {
bool eof = false;
for (std::streambuf *buf : buffers)
eof |= (buf->sputc(c) == traits_type::eof());
return eof ? traits_type::eof() : c;
}
};
class logstream : public std::ostream {
std::vector<std::ofstream *> streams;
buf outputs;
logger log;
void attach(std::ostream &s) { outputs.attach(s.rdbuf()); }
void attach(char const *name) {
std::ofstream *s = new std::ofstream(name);
streams.push_back(s);
outputs.attach(s->rdbuf());
}
template <typename T, typename...pack>
void attach(T &t, pack&...p) {
attach(t);
attach(p...);
}
public:
template <typename...pack>
logstream(pack&...p) : log(&outputs), std::ostream(&log) { attach(p...); }
~logstream() {
for (auto d : streams) {
d->close();
// Bug: crashes with g++ if delete is allowed to execute.
//delete d;
}
}
};
}
#endif
Then the demo of how to use it:
#include "logger"
int main(){
multi::logstream l(std::cout, "c:/path/log.txt");
l << "This is a prefixed string\n";
}
Obviously the header is fairly large, but the code to use it seems (at least to me) about as simple as you can hope for -- create an object, specifying where you want the output to go, just a normal stream -- except that you can specify more than one. Then write to it like you would to any other stream, and the output goes to all of the specified outputs, with each line preceded by the specified prefix.
I have a class that I want to give an output stream as a member to, to wit:
class GameBase {
protected:
ofstream m_OutputWriter;
...
}
There is a method in this class that takes a string argument and opens m_OutputWriter to point to that file, so data may be output to that file by using the standard << operator;
However, what I would like is to make the stream point to cout by default, so that if the output path is not specified, output goes to the console output instead of to a file, and it will be completely transparent by the calling class, who would use
m_OutputWriter << data << endl;
to output the data to the predetermined destination. Yet, I have tried a couple of the other examples here, and none of them exactly seem to fit what I'm trying to do.
What am I missing here?
Why does the stream need to be a member?
struct GameBase {
void out(std::ostream& out = std::cout);
// ...
};
In addition to having an std::ofstream as a member, I would use a function that returns an std::ostream&.
For example:
class GameBase {
std::ofstream m_OutputWriter;
protected:
std::ostream& getOutputWriter() {
if (m_OutputWriter)
return m_OutputWriter;
else
return std::cout;
}
...
}
A fully-functioning example:
#include <iostream>
#include <ostream>
std::ostream& get() {
return std::cout;
}
int main() {
get() << "Hello world!\n";
}