I get this assignment.
Implement a RAII Logger class that will print a line to a specified output stream in its constructor and destructor.
- The class will receive an output stream and some text in its constructor.
- It will print
[start]
in its constructor and[end]
in its destructor to the specified output stream (std::ostream&
).- Each logger will print its output with some indent (number of space characters printed before the actual content of the line).
- When you create a logger with a constructor, it will have indent of
0
space characters.- The Logger will also have a method called
sublogger
, which will receive text to be printed.
- It will return a new logger that will use the same output stream,
- it will have its indent increased by
2
- and it will print the provided
text
.- Make sure that the class cannot be copied or copy assigned.
Anyone to give me some advice how to get this? Thank you for any advice.
Example:
{
Logger logger(std::cout, "foo"); // prints "foo [start]"
} // prints "foo [end]"
{
Logger l1(std::cout, "l1"); // prints "l1 [start]"
{
Logger l2 = l1.sublogger(); // prints " l2 [start]"
} // prints " l2 [end]"
} // prints "l1 [end]"
Now I am able to get this:
l1 [start]
l2 [start]
l3 [start]
l3 [end]
l4 [start]
l4 [end]
l2 [end]
l1 [end]
But I need this:
l1 [start]
l2 [start]
l3 [start]
l3 [end]
l4 [start]
l4 [end]
l2 [end]
l1 [end]
tasks.h
#pragma once
#include <string>
#include <iostream>
class Logger {
std::ostream& a;
std::string b;
std::string strOffset;
public:
Logger(std::ostream& a, std::string b);
~Logger();
Logger sublogger(std::string sub);
};
tasks.cpp
#include "tasks.h"
Logger::Logger(std::ostream& a, std::string b) : a(a), b(b) {
a << strOffset << b << " [start]" << std::endl;
}
Logger::~Logger() {
a << b << " [end]" << std::endl;
}
Logger Logger::sublogger(std::string sub) {
return Logger(a, sub);
};
This is how test case looks like:
TEST_CASE("Create subloggers") {
std::stringstream ss;
{
Logger logger(ss, "l1");
{
auto logger2 = logger.sublogger("l2");
{
auto logger3 = logger2.sublogger("l3");
}
auto logger4 = logger.sublogger("l4");
}
}
std::string testString = ss.str();
REQUIRE(ss.str() == R"(l1 [start]
l2 [start]
l3 [start]
l3 [end]
l4 [start]
l4 [end]
l2 [end]
l1 [end]
)");
CodePudding user response:
I don't know what a RAAI Logger is, so it might not be it, but it works for your test case:
tasks.cpp
#include "tasks.h"
Logger::Logger(std::ostream& a, std::string b) : a(a), b(b), offset(0) {
a << b << " [start]" << std::endl;
}
Logger::Logger(std::ostream& a, std::string b, int offset) : a(a), b(b), offset(offset) {
printOffset();
a << b << " [start]" << std::endl;
}
Logger::~Logger() {
printOffset();
a << b << " [end]" << std::endl;
}
void Logger::printOffset() {
for(int i = 0; i < offset; i ) {
a << " ";
}
}
Logger Logger::sublogger(std::string sub) {
return Logger(a, sub, offset 1);
};
tasks.h
#pragma once
#include <string>
#include <iostream>
class Logger {
std::ostream& a;
std::string b;
int offset;
void printOffset();
public:
Logger(std::ostream& a, std::string b);
Logger(std::ostream& a, std::string b, int offset);
~Logger();
Logger sublogger(std::string sub);
};
CodePudding user response:
class Logger {
std::ostream& out;
const std::string name;
const std::string prefix;
public:
Logger(std::ostream& stream, std::string name);
~Logger();
Logger sublogger(std::string sub);
private:
Logger(std::ostream& stream, std::string name, std::string prefix);
Logger(const Logger&) = default;
Logger(Logger&&) = default;
Logger& operator=(const Logger&) = delete;
Logger& operator=(Logger&&) = delete;
};
Logger::Logger(std::ostream& stream, std::string name, std::string prefix)
: out(stream)
, name(name)
, prefix(prefix)
{
out << prefix << name << " [start]" << std::endl;
}
Logger::Logger(std::ostream& stream, std::string name)
: Logger(stream, name, {})
{
}
Logger::~Logger()
{
out << prefix << name << " [end]" << std::endl;
}
Logger Logger::sublogger(std::string sub)
{
return Logger(out, sub, prefix " ");
};