I included the logger from boost. I'm pretty pleased how it works. Just for simplicity and the reason I don't want to use makros to often in my code, I wrap it in a class.
I now wonder if I could use the streaming operator << to write on a member function.
code
class LogWrapper{
...
//debug function
//info function
...
}
void main() {
LogWrapper log;
log.debug() << "some debug msg"; // does this exist?
log.info() << "some info msg";
}
output
[some_timestamp][debug] some debug msg
[some_timestamp][info] some info msg
Is this possible in a good practice, or is it entirely bad style?
It can be done easily like this:
#include <iostream>
class A {
public:
std::ostream &debug() const {
std::cerr << "[timestamp]" << "[DEBUG]";
return std::cerr;
}
};
int main()
{
A a;
a.debug() << "Test";
}
But the important question here is: Should we implement it in this way? In my opinion, NO!
Because you are thinking that the User of the class will print the logs like this:
int main()
{
A a;
a.debug() << "Test" << std::endl;
a.debug() << "Test2" << std::endl;
}
Output:
[timestamp][DEBUG]Test
[timestamp][DEBUG]Test2
But what if User chooses this way:
int main()
{
A a;
auto &out = a.debug();
out << "Test" << std::endl;
out << "Test2" << std::endl;
}
Output:
[timestamp][DEBUG]Test
Test2
I would highly recommend not to return stream object. You should use member functions for this purpose.
#include <iostream>
class A {
public:
static void debug(const std::string &log) {
std::cerr << "[timestamp]" << "[DEBUG]" << log << std::endl;
}
};
int main()
{
A::debug("Test 1");
A::debug("Test 2");
}
Output:
[timestamp][DEBUG]Test 1
[timestamp][DEBUG]Test 2
Related
I got this:
class Core
{
protected:
static unsigned int id_seed;
unsigned int id;
std::string status;
public:
friend class CPU;
Core();
~Core();
virtual void procesare(std::string aplicatie) = 0;
};
class CoreScreen: public Core
{
public:
CoreScreen();
~CoreScreen();
void procesare(std::string aplicatie);
};
and corescreen.cpp:
#include "CoreScreen.h"
CoreScreen::CoreScreen()
{
}
CoreScreen::~CoreScreen()
{
}
void CoreScreen::procesare(std::string aplicatie)
{
std::string buffer;
std::ifstream file_in(aplicatie);
if (file_in.is_open()) {
std::cout << "Aplicatia " << aplicatie << " ruleaza: " << std::endl;
while (getline(file_in, buffer)) {
std::cout << buffer;
}
file_in.close();
}
else {
throw new CExceptie(APP_FAIL, " Aplicatia nu a putut rula!");
}
}
When I use in main:
CoreScreen CS1, CS2, CS3, CS4;
I get this error: 'Core' cannot instantiate abstract class.
What's the problem? I thought I have my virtual function declared in CoreScreen correctly.
As I presume you know, "Core" is an abstract class, by virtue of the fact it has a pure virtual function: virtual void procesare(std::string aplicatie) = 0;.
I presume you also know that you can't instantiate an abstract class: hence your error.
The question is:
Why does the compiler think you're trying to instantiate an instance of "Core"?
Are you?
It looks like you're trying to instantiate four CoreScreen objects: CoreScreen CS1, CS2, CS3, CS4;. If so, that should be perfectly OK.
You're correct: procesare() is virtual ("pure virtual", as it happens). You've indeed overridden it correctly in CoreScreen.cpp: it DOESN'T look like that's the problem.
Q: Did you ever implement Core::Core() and Core::~Core() anywhere? If not, how did you even compile?
Q: Are you SURE you're not trying to create an instance of "Core" anywhere (even "accidentally")?
For whatever it's worth, the following MCVE compiles and runs fine (Ubuntu 18, GCC 7.3.0):
TestCore.h:
/*
* TestCore.h
*/
#ifndef TESTCORE_H_
#define TESTCORE_H_
#include <string>
class Core
{
protected:
static unsigned int id_seed;
unsigned int id;
std::string status;
public:
friend class CPU;
Core();
~Core();
virtual void procesare(std::string aplicatie) = 0;
};
class CoreScreen: public Core
{
public:
CoreScreen();
~CoreScreen();
void procesare(std::string aplicatie);
};
#endif /* TESTCORE_H_ */
TestCore.cpp:
/*
* TestCore.cpp
*/
#include <iostream>
#include <fstream>
#include "TestCore.h"
Core::Core()
{
std::cout << "Core::Core()..." << std::endl;
}
Core::~Core()
{
std::cout << "Core::~Core()..." << std::endl;
}
CoreScreen::CoreScreen()
{
std::cout << "CoreScreen::CoreScreen()..." << std::endl;
}
CoreScreen::~CoreScreen()
{
std::cout << "CoreScreen::~CoreScreen()..." << std::endl;
}
void CoreScreen::procesare(std::string aplicatie)
{
std::cout << "CoreScreen::procesare(" << aplicatie << ")" << std::endl;;
}
int main () {
std::cout << ">>main()..." << std::endl;
CoreScreen CS1, CS2, CS3, CS4;
CS1.procesare("Testing CS1");
std::cout << "<<main()." << std::endl;
return 0;
}
SAMPLE OUTPUT:
>>main()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
Core::Core()...
CoreScreen::CoreScreen()...
CoreScreen::procesare(Testing CS1)
<<main().
You'll note that I implemented Core::Core() and Core::~Core(). If you don't need them - then don't even put them in your .h class definition.
'Hope that helps
i search for a way to call a method by its string name.
#include <iostream>
#include <string>
class myClass{
public:
void method1(int run){
std::cout << run << std::endl;
}
void method2(int run){
std::cout << run << std::endl;
}
};
int main(){
myClass mc;
std::string call;
call = "method1";
mc.call(1);
call = "method2";
mc.call(2);
}
But the result, is
‘class Myclass’ has no member named ‘call’
I need response "1" and "2";
EDIT :: Very thank's for your help, i get the next solution (i don't know is good for all cases );
#include <iostream>
#include <string>
class myClass{
public:
void method1(int run){
std::cout << "Loaded method => " << run << std::endl;
}
void method2(int run){
std::cout << "Loaded method => " << run << std::endl;
}
void _loadMethods(int method, int params){
switch(method) {
case 1:
method1(params);
break;
case 2:
method2(params);
break;
default:
break;
}
}
};
int main(){
myClass mc;
std::string method;
method = "method2";
if(method == "method1"){
mc._loadMethods(1, 1);
}
if(method == "method2"){
mc._loadMethods(2, 2);
}
}
Thank's
This is not possible in "raw" C++. But... What you are trying to achieve is some kind of Reflection or Class meta-type information.
You can look at this project: http://www.axelmenzel.de/projects/coding/rttr , use Qt: http://doc.qt.io/qt-5/qmetatype.html#details or google for C++ reflection.
Suppose that I want to create a stream that would perform an action at the end of the statement, so that
myStream << "Hello, " << "World!";
would print "Hello, World!\n" in one shot. Not "Hello, \nWorld!\n" and not "Hello, World!", but "Hello, World\n", as if ; would trigger appending \n and flushing the buffers.
The rationale for that is a stream class that writes to both stdout and a logfile, with the logfile entries having certain prefixes and suffixes.
For example, if my target was HTML I would want this code:
myStream << "Hello, " << "World!";
myStream << "Good bye, " << "cruel World!";
to print like this:
<p>Hello, World!</p>
<p>Good bye, cruel World!</p>
and not like this:
<p>Hello, </p><p>World!</p>
<p>Good bye, </p><p>cruel World!</p>
Now, if I implement LogStream sort of like this:
LogStream & LogStream::operator<<( const std::string & text );
I won't be able to distinguish between << in the middle of the statements from the ones in the beginning/ending of the statements.
If I implement LogStream sort of like this:
LogStream LogStream::operator<<( const std::string & text );
and try to massage the input in the destructor I would get multiple destructors at once at the end of the block.
Finally, I can implement this my requiring endl at the end of each statement, but I'd rather not bother the caller with the necessity to do so.
Thus the question: how one implements such a stream in a caller-transparent fashion?
I implemented something like this once for a custom logging system. I created a class that buffered input and then its destructor flushed the buffer to my log file.
For example:
#include <iostream>
#include <sstream>
#include <string>
class LogStream
{
private:
std::stringstream m_ss;
void flush()
{
const std::string &s = m_ss.str();
if (s.length() > 0)
{
std::cout << s << std::endl;
logfile << "<p>" << s << "</p>" << std::endl;
}
}
public:
LogStream() {}
~LogStream()
{
flush();
}
template <typename T>
LogStream& operator<<(const T &t)
{
m_ss << t;
return *this;
}
template <typename T>
LogStream& operator<<( std::ostream& (*fp)(std::ostream&) )
{
// TODO: if fp is std::endl, write to log and reset m_ss
fp(m_ss);
return *this;
}
void WriteToLogAndReset()
{
flush();
m_ss.str(std::string());
m_ss.clear();
}
};
For single statements that flush on the final ;, each message would use a new instance of the class:
LogStream() << "Hello, " << "World!";
LogStream() << "Good bye, " << "cruel World!";
To allow multiple statements to write to a single message, create the object and do not let it go out of scope until the last statement is done:
{
LogStream myStream;
myStream << "Hello, ";
myStream << "World!";
}
{
LogStream myStream;
myStream << "Good bye, ";
myStream << "cruel World!";
}
To reuse an existing instance for multiple messages, tell it to flush and reset in between each message:
{
LogStream myStream;
myStream << "Hello, " << "World!";
myStream.WriteToLogAndReset();
myStream << "Good bye, " << "cruel World!";
}
I like this approach because it gives the caller more flexibility in deciding when each message is ready to be written to the log file. For instance, I use this to send multiple values to a single log message where those values are obtained from decision-making code branches. This way, I can stream some values, make some decisions, stream some more values, etc and then send the completed message to the log.
The line:
myStream << "Hello, " << "World!";
Is actually multiple statements. It's equivalent to:
ostream& result = myStream << "Hello, ";
result << "World!";
There are some tricks to do what you want by returning an unnamed temporary object (which are destroyed at the end of the full-expression). Here is some example code.
I have a little code that I haven't gotten round to doing anything constructive with that I think is doing what you're asking.
It works by using a proxy class (log_buffer) to build up the string in a std::stringstream object. At the end of the expression the log_buffer proxy object calls the main log_writer
object to process the whole line contained in the std::stringstream.
class log_writer
{
// ultimate destination
std::ostream* sink = nullptr;
// proxy class to do the << << << chaining
struct log_buffer
{
log_writer* lw;
std::stringstream ss;
void swap(log_buffer& lb)
{
if(&lb !=this)
{
std::swap(lw, lb.lw);
std::swap(ss, lb.ss);
}
}
log_buffer(log_writer& lw): lw(&lw) {}
log_buffer(log_buffer&& lb): lw(lb.lw), ss(std::move(lb.ss)) { lb.lw = nullptr; }
log_buffer(log_buffer const&) = delete;
log_buffer& operator=(log_buffer&& lb)
{
swap(lb);
return *this;
}
log_buffer& operator=(log_buffer const&) = delete;
// update the log_writer after the last call to << << <<
~log_buffer() { if(lw) lw->add_line(ss); }
template<typename DataType>
log_buffer operator<<(DataType const& t)
{
ss << t;
return std::move(*this);
}
};
void swap(log_writer& lw)
{
if(&lw != this)
{
std::swap(sink, lw.sink);
}
}
public:
log_writer(std::ostream& sink): sink(&sink) {}
log_writer(log_writer&& lw): sink(lw.sink) { lw.sink = nullptr; }
log_writer(log_writer const&) = delete;
log_writer& operator=(log_writer&& lw)
{
swap(lw);
return *this;
}
log_writer& operator=(log_writer const&) = delete;
// output the final line
void add_line(std::stringstream& ss)
{
// Do any special line formatting here
if(sink) (*sink) << ss.str() << std::endl;
}
template<typename DataType>
struct log_buffer operator<<(DataType const& data)
{
return std::move(log_buffer(*this) << data);
}
};
int main()
{
std::ofstream ofs("test.log");
log_writer lw1(ofs);
log_writer lw2(std::cout);
lw1 << "lw1 " << 2.93 << " A";
lw2 << "lw2 " << 3.14 << " B";
std::swap(lw1, lw2);
lw1 << "lw1 " << 2.93 << " C";
lw2 << "lw2 " << 3.14 << " D";
}
I'm searching the best way to add a custom, initial message to all the messages that std::cout (or std::cerr) prints to console/file output.
For example, if I setup that this custom prompt message will be the string "[Log]", then a classic
std::cerr << "This is a log message" << std::endl;
will be printed in this way:
> [Log] This is a log message
Clearly I can obtain this behavior using
std::string PROMPT_MSG = "[Log]";
std::cerr << PROMPT_MSG << "This is a log message" << std::endl;
but I'd like a less invasive way.
Thanks in advance
You could write your own class:
#include <iostream>
#include <string>
class MyLogger
{
std::ostream & out;
std::string const msg;
public:
MyLogger(std::ostream & o, std::string s)
: out(o)
, msg(std::move(s))
{ }
template <typename T>
std::ostream & operator<<(T const & x)
{
return out << msg << x;
}
};
MyLogger MyErr(std::cerr, "[LOG] ");
Usage:
MyErr << "Hello" << std::endl;
As Joachim Pileborg suggested you can use a logging framework. YOu can use an existing one or start with your own that will contain just one class:
class MyLogger{}
template <typename T>
MyLogger& operator << (MyLogger& logger, const T& logStuff)
{
std::cerr << PROMPT_MSG << logStuff << std::endl;
return logger;
}
then define a global variable of class MyLogger:
MyLogger mylogger;
then when you want to write a log record, write:
mylogger << "This is a log message";
overloaded operator << of class MyLogger will do what you want;
I had the same problem in a recent project. I solved it with this little class:
class DebugOut
{
public:
static const int COLUMN_WIDTH = 15;
DebugOut(const std::wstring &type)
{
std::wcout << type;
for(int i=type.length();i<COLUMN_WIDTH;i++)
std::wcout << " ";
std::wcout << ": ";
}
~DebugOut()
{
std::wcout << std::endl;
}
template <typename T>
friend DebugOut& operator<<(DebugOut& out,T i)
{
std::wcout << i;
return out;
}
};
Sample usage: DebugOut(L"Log") << "Something";
I guess you could just define a function log and a function error, and then just call them when you want to print a log or error method. That way you don't have to add the PROMPT_MSG every time.
I want to create a class which would help me with debugging by providing std::cout or QDebug like functionality using a 3D renderer.
I have the following renderer method which I'm using now
IRenderer::renderText(int posX, int posY, const float* color, const char* text, ...);
// E.g.
int i;
float f;
float color[] = {1, 1, 1, 1};
renderer->renderText(50, 50, color, "Float %f followed by int %i", f, i);
This actually works fine, but I wonder if it's possible to create a class which would allow me to do it like this:
debug() << "My variables: " << i << ", " << "f";
I assume there would be a template function which would build the string to pass to renderText() based on input type, but I'm not quite sure how to implement it.
An alternative to Rob's answer is to include an ostringstream in your custom logger class, and use the destructor to do the logging:
#include <iostream>
#include <sstream>
class MyLogger
{
protected:
std::ostringstream ss;
public:
~MyLogger()
{
std::cout << "Hey ma, I'm a custom logger! " << ss.str();
//renderer->renderText(50, 50, color, ss.str());
}
std::ostringstream& Get()
{
return ss;
}
};
int main()
{
int foo = 12;
bool bar = false;
std::string baz = "hello world";
MyLogger().Get() << foo << bar << baz << std::endl;
// less verbose to use a macro:
#define MY_LOG() MyLogger().Get()
MY_LOG() << baz << bar << foo << std::endl;
return 0;
}
I like to derive my logging class from std::ostream, so I get all of the stream goodness. The trick is to put all of your application-specific code in the associated streambuf class. Consider this working example. To modify it to meed your needs, simply rewrite CLogBuf::sync(), like so:
int sync() {
renderer->renderText(50, 50, color, "%s", str());
str("");
return false;
}
Example:
#include <iostream>
#include <sstream>
class CLogger : public std::ostream {
private:
class CLogBuf : public std::stringbuf {
private:
// or whatever you need for your application
std::string m_marker;
public:
CLogBuf(const std::string& marker) : m_marker(marker) { }
~CLogBuf() { pubsync(); }
int sync() { std::cout << m_marker << ": " << str(); str(""); return !std::cout; }
};
public:
// Other constructors could specify filename, etc
// just remember to pass whatever you need to CLogBuf
CLogger(const std::string& marker) : std::ostream(new CLogBuf(marker)) {}
~CLogger() { delete rdbuf(); }
};
int main()
{
CLogger hi("hello");
CLogger bye("goodbye");
hi << "hello, world" << std::endl;
hi << "Oops, forgot to flush.\n";
bye << "goodbye, cruel world\n" << std::flush;
bye << "Cough, cough.\n";
}