reduce code duplication in c++ - c++

Can I reduce the following code to one function? the most part of them are the same. Thanks
void info(StreamLog &streamLog)
{
streamLog.ss << "info:";
streamLog.mFilter->setLogLevel("info");
}
void debug(StreamLog &streamLog)
{
streamLog.ss << "debug:";
streamLog.mFilter->setLogLevel("debug");
}
void warning(StreamLog &streamLog)
{
streamLog.ss << "warning:";
streamLog.mFilter->setLogLevel("warning");
}
void error(StreamLog &streamLog)
{
streamLog.ss << "error:";
streamLog.mFilter->setLogLevel("error");
}
void critical(StreamLog &streamLog)
{
streamLog.ss << "critical:";
streamLog.mFilter->setLogLevel("critical");
}
if you need more info,let me know
1st edited:
sorry ! I didnt explain my situation clearly. I use those function as manipulator. therefore, i can do
clog << info << ...
clog << warning<<...
I dont want to use
clog << log(info) <<...
any better way? thanks

void log(StreamLog &streamLog, const string& level)
{
streamLog.ss << level << ":";
streamLog.mFilter->setLogLevel(level);
}
Always try to see the common operation and abstract it in a different function.

I'm with #Rémi Benoit, though to provide you with an alternative, you can use an enum and a map:
enum log_level {
info, debug, warning, error, critical
}
void log(StreamLog& streamLog, log_level level) {
static const std::map<log_level, std::string> levels = {
{ info, "info" }, { debug, "debug" }, { warning, "warning" },
{ error, "error" }, { critical, "critical" }
};
auto iter = levels.find(level);
if(iter == levels.end()) return;
streamLog.ss << iter->second;
streamLog.mFilter->setLogLevel(iter->second);
}
The benefit of this is that your log level is limited only to what is in the enum (and the map), though if you do not require this constraint, it is better to use #Rémi's solution.

Here is an alternative to Mark's & Rémi's solutions using templates. This solution could be useful in areas where high performance is critical. The templates let the compiler bake in a lot of information into each templated function already so there should be a smaller run time cost especially when compared to the map lookup method.
Additionally this will constrain the values for the log_level being used at compile time rather than at run time.
enum class log_level { info, debug, warning, error, critical };
template<log_level> struct log_helper{ static const char* const text; };
template<> const char* const log_helper<log_level::info>::text = "info";
template<> const char* const log_helper<log_level::debug>::text = "debug";
template<> const char* const log_helper<log_level::warning>::text = "warning";
template<> const char* const log_helper<log_level::error>::text = "error";
template<> const char* const log_helper<log_level::critical>::text = "critical";
template<log_level level> void set_log_level(StreamLog& streamLog)
{
streamLog.ss<< log_helper<level>::text << ":";
streamLog.mFilter->setLogLevel(log_helper<level>::text);
}

Related

How to defer computation in C++ until needed?

In C++(*), is it possible to have a structure that "defers" some computation until needed (and maybe never does the computation if not necessary)? My use case is as follows: I have roughly a dozen bool variables, each of which is computed with some function call. Following that, there is a rather long (and complex) conditional statement that uses those bool variables in different combinations to determine what action the code will take next.
Here is some contrived sample code to hopefully better illustrate what I'm doing:
bool const b1 = func1(param1,param2,param3);
bool const b2 = func2(param4);
// ...
bool const b15 = func15(param35,param36,param37,param38);
if (b1 && !b5 && (b2 || b3)) { do_something1(); }
else if (b3 && !b15 || (b4 && b9 && b6)) { do_something2(); }
else if (b14 || b10 || (!b11 && b7)) { do_something3(); }
else if (b8) {
if (!b1 || !b6) { do_something4(); }
else if ( /* ... */ ) // ... etc
}
// ... and on and on
That is a purely contrived example, but hopefully it illustrates the idea.
Clearly this code could be re-written without the bools, and the functions called directly in the big conditional statement. But I feel that would make the already not-easy-to-read code even harder to read, and more error prone. And this logic could change, so I feel the bools make it easier to manage from a refactoring perspective as well.
Furthermore, any bool might be referenced multiple times within the conditional; so using the functions directly means execution could be duplicated. (I was thinking std::bind might get me there from a readability perspective; but it would still potentially call any of the funcN() calls multiple times.)
What I'm looking for is the best of both words, like a "deferred" compute. What if instead of being computed and assigned explicitly at the start of the code, I could say, "only evaluate these as needed (and remember the result)". The big conditional statement is such that, generally, not all bools actually need to be computed to determine what happens next. The goal here is improved performance, as this code is called often. So I'm trying to reduce the amount of work done on each iteration.
(*) Preferably C++14 (or older), as that's what my employer is using.
Edit: What about something like this:
#include <iostream>
#include <functional>
//////////////////////////////////////////////////////////////////////////////
class Sum
{
public:
int sum(int const a, int const b) { ++n_calls_; return (a+b); }
int getNCalls() const { return n_calls_; }
private:
int n_calls_ = 0;
};
//////////////////////////////////////////////////////////////////////////////
template <class BoundFunc, typename RetType>
class DeferredCompute
{
public:
DeferredCompute(BoundFunc const& f) : func_(f) { }
RetType operator()()
{
if (!computed_)
{
value_ = func_();
computed_ = true;
}
return value_;
}
private:
bool computed_ = false;
RetType value_;
BoundFunc const& func_;
};
//////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
Sum s;
auto boundSum = std::bind(&Sum::sum, &s, 75, 25);
DeferredCompute<decltype(boundSum), int> deferredSum(boundSum);
// call function directly repeatedly
for (int i=0; i<5; ++i)
{
std::cout << "boundSum()=" << boundSum() << std::endl;
}
std::cout << "s.getNCalls()=" << s.getNCalls() << std::endl;
// should only call once
for (int i=0; i<5; ++i)
{
std::cout << "deferredSum()=" << deferredSum() << std::endl;
}
std::cout << "s.getNCalls()=" << s.getNCalls() << std::endl;
return 0;
}
Output:
boundSum()=100
boundSum()=100
boundSum()=100
boundSum()=100
boundSum()=100
s.getNCalls()=5
deferredSum()=100
deferredSum()=100
deferredSum()=100
deferredSum()=100
deferredSum()=100
s.getNCalls()=6
std::async with the option std::launch::deferred is what you're looking for.
https://en.cppreference.com/w/cpp/thread/async
eg
auto future = std::async(std::launch::deferred, [](){return 5;});
// future isn't calculated yet
auto result = future.get();
// result = 5, and will remain cached while in scope.
At first, I would try using some lambda-closures.
const auto b1 = [&]() { return func1(param1,param2,param3); };
const auto b2 = [&]() { return func2(param4); };
// ...
const auto b15 = [&]() { return func15(param35,param36,param37,param38); };
if (b1() && !b5() && (b2() || b3())) { do_something1(); }
...
If you need to cache the bool results but not for the entire
lifetime of the program (static), this solution could
make it (three levels of lambda-closure; it's "Inception").
/**
g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <iostream>
void
test(int i)
{
auto cache=[](auto expr)
{
return [expr, res=false, done=false]() mutable
{
if(!done) { res=expr(); done=true; }
return res;
};
};
auto b1=cache([&]() { std::cout << "(eval b1)"; return i>2; });
auto b2=cache([&]() { std::cout << "(eval b2)"; return i<5; });
std::cout << "1: b1=" << b1() << " b2=" << b2() << '\n';
std::cout << "2: b1=" << b1() << " b2=" << b2() << '\n';
}
int
main()
{
for(int i=0; i<6; ++i)
{
std::cout << "~~~~~~~~\n";
test(i);
}
return 0;
}
/**
~~~~~~~~
1: b1=(eval b1)0 b2=(eval b2)1
2: b1=0 b2=1
~~~~~~~~
1: b1=(eval b1)0 b2=(eval b2)1
2: b1=0 b2=1
~~~~~~~~
1: b1=(eval b1)0 b2=(eval b2)1
2: b1=0 b2=1
~~~~~~~~
1: b1=(eval b1)1 b2=(eval b2)1
2: b1=1 b2=1
~~~~~~~~
1: b1=(eval b1)1 b2=(eval b2)1
2: b1=1 b2=1
~~~~~~~~
1: b1=(eval b1)1 b2=(eval b2)0
2: b1=1 b2=0
**/
For the sake of readability and maintainability you could organise the program as a state machine. That provides you with the benefit of separating the state transitions and actions from one another, plus it should be reasonably simple to rewire the logic later should the necessity arise.
See here for some examples:
C++ code for state machine
What if instead of being computed and assigned explicitly at the start of the code, I could say, "only evaluate these as needed (and remember the result)"
/// #brief only evaluate these as needed (and remember the result)
class lazy final
{
mutable std::future<bool> value_;
public:
template<typename Functor>
lazy(Functor &&f)
: value_{ std::async(std::launch::deferred,
std::forward<Functor>(f)) }
{
}
operator bool() const
{
return value_.get();
}
};
client code:
auto b1 = lazy::lazy{[&]{ return func1(param1,param2,param3); }};
auto b2 = lazy::lazy{[&]{ return func2(param4); }};
// ...
bool const b15 = lazy::lazy{[&]{ return func15(param35,param36,param37,param38); }};
// rest remains the same as your contrieved example
I have not compiled this code. If working in c++14 (as you mention) you may need a factory function similar to this:
template<typename Functor>
auto make_lazy(Functor&& f) { return lazy<Functor>(std::forward<Functor>(f)); }
The only thing that changes is the declaration of your bX variables. You may also consider adding code that tells you how often each lazy evaluation is called in practice, declaring those bX variables first, and launching them immediately, in parallel, instead of in a deferred manner. But only do that after you measure performance both ways.

Class design - use optionals? variants? be opaque?

I want to have a class for PCI bus locations. For the sake of discussion, these come in three forms:
[domain]:[bus]:[device].[function]
[domain]:[bus]:[device]
[bus]:[device].[function]
and let's say each field is a non-negative integral value (let's even say unsigned just to make things simple).
I'm scratching my head regarding how to define this class. I could use std::optionals for the domain and function fields; but then, they're not both optional. I could use a variant with 3 types, but then I need to define separate types, which overlap a lot. I could just hold 4 unsigneds and a 3-value enum for which format is in effect - but that's quite a bit of hassle, and I'd need getter and to make the class opaque. Same thing if I try to use a union somehow.
It seems like every choice I make, it's going to be an iffy class. How can I minimize my displeasure with it?
Note: Any language standard version is ok for the answer, although I doubt C++20 would give you anything.
Building upon my comment, I was wondering if something like this could work:
enum class pci_format { domain_function, domain, function };
template <pci_format E> struct tag { };
class pci_location {
public:
pci_location (tag<pci_format::domain_function>, unsigned domain, unsigned bus,
unsigned device, unsigned function)
: format_(pci_format::domain_function)
, domain_(domain)
, bus_(bus)
, device_(device)
, function_(function)
{ }
// Repeat for other values of pci_format.
pci_format format () const { return format_; }
bool has_domain () const {
return (format_ == pci_format::domain_function)
or (format_ == pci_format::domain);
}
unsigned domain () const {
if (not has_domain()) { throw std::runtime_error("Domain not available."); }
return domain_;
}
// Repeat for other fields.
private:
pci_format format_;
unsigned domain_;
unsigned bus_;
unsigned device_;
unsigned function_
};
You would basically create a specific constructor for each PCI "format". Of course you could also store each unsigned as an std::optional<unsigned>, but that would force users to "dereference" each optional even if they knew for sure that it must contain a value.
One way or another, they'll have to check what "format" the location is in, so it seems to me that using an enum for this is more user friendly. Then users only have to check once and know exactly which fields are available.
I guess you could layer a visitor on top of all this so they can simply provide code to execute for each "format":
struct pci_location_visitor {
virtual void visit (tag<pci_format::domain_function>, pci_location const & obj) = 0;
// Repeat for other enum values.
};
// Add to pci_location:
void accept (pci_location_visitor & visitor) {
switch (format_) {
case pci_format::domain_function:
return visitor.visit(tag<pci_format::domain_function>{}, *this);
default: throw std::runtime_error("Format not supported for visitation.");
}
}
Then on top of that you could create a visitor that can be constructed from a bunch of callables, i.e. lambdas, so that this all can be used like below:
pci_location const & loc = getIt();
auto printSomething = make_pci_location_visitor(
[](tag<pci_format::domain_function>, pci_location const & e) { std::cout << e.domain(); }
, [](tag<pci_format::domain>, pci_location const & e) { std::cout << e.bus(); }
, [](tag<pci_format::function>, pci_location const & e) { std::cout << e.function(); }
);
loc.accept(printSomething);
For an example of how such a visitor could be constructed, see the overloaded class in the std::visit example on cppreference.com.
As requested in comments... given that I have no particular requirements how the users would prefer to use this class, given C++14, I would be doing something generic along the lines of:
#include <array>
#include <climits>
#include <iostream>
#include <stdexcept>
class pci_location_t {
public:
struct dbdf {
unsigned int domain;
unsigned int bus;
unsigned int device;
unsigned int function;
};
struct dbd {
unsigned int domain;
unsigned int bus;
unsigned int device;
};
struct bdf {
unsigned int bus;
unsigned int device;
unsigned int function;
};
pci_location_t(dbdf v) : domain(v.domain), bus(v.bus), device(v.device), function(v.function) {}
pci_location_t(dbd v) : domain(v.domain), bus(v.bus), device(v.device), function(INVALID) {}
pci_location_t(bdf v) : domain(INVALID), bus(v.bus), device(v.device), function(v.function) {}
template <typename dbdf_f, typename dbd_f, typename bdf_f>
auto visit(dbdf_f dbdf_fun, dbd_f dbd_fun, bdf_f bdf_fun) const {
if (domain == INVALID) {
if (function == INVALID) {
throw std::domain_error("Wrong PCI location format");
}
return bdf_fun(bdf{bus, device, function});
} else if (function == INVALID) {
return dbd_fun(dbd{domain, bus, device});
} else {
return dbdf_fun(dbdf{domain, bus, device, function});
}
}
private:
friend pci_location_t invalid_location();
pci_location_t() : domain(INVALID), bus(INVALID), device(INVALID), function(INVALID) {}
const static unsigned int INVALID = UINT_MAX;
unsigned int domain;
unsigned int bus;
unsigned int device;
unsigned int function;
};
pci_location_t invalid_location() { return pci_location_t{}; }
int main() {
std::array<pci_location_t, 4> locations = {
pci_location_t(pci_location_t::dbdf{1, 2, 3, 4}),
pci_location_t(pci_location_t::dbd{1, 2, 3}),
pci_location_t(pci_location_t::bdf{2, 3, 4}),
invalid_location()
};
try {
for (auto& l : locations) {
l.visit(
[] (auto dbdf) {
std::cout << dbdf.domain << ":" << dbdf.bus << ":" << dbdf.device << "." << dbdf.function << std::endl;
},
[] (auto dbd) {
std::cout << dbd.domain << ":" << dbd.bus << ":" << dbd.device << std::endl;
},
[] (auto bdf) {
std::cout << bdf.bus << ":" << bdf.device << "." << bdf.function << std::endl;
}
);
}
std::cout << "Done!" << std::endl;
} catch(const std::exception& e) {
std::cout << e.what() << std::endl;
}
return 0;
}
(you can check it on Coliru).
Feel free to use optionals or a separate format field if you don't like special values.
I'd make both the domain and the function optional (I don't really care how, as long as it's effective), and just enforce the only-one-missing condition as a class invariant. That is, only the functions that can change any of the fields need to perform the check and signal possible errors back to the user. No need to bloat your code with variants, or with dynamically interpreted unsigned int arrays. KISS.

std::clog wrapper with color and header fails to print integers properly

I need a class to wrap calls to std::clog so that:
Each message is prefixed by a header that includes time and the name of the entity that generated the message.
Messages are coloured in accordance to error types (e.g. debug, warning, error).
The way to use it is exactly equivalent to std::clog << "..." for all its features (i.e. the ability to have implicit basic type-to-string conversions, stream manipulators, flushing, etc.)
My attempt has been based on many examples found in this forum (*), but I guess in a kind of a wrong way, because my class is a bit faulty.
Essentially what I tried is to extend std::streambuf by overriding the overflow and xputn methods in a way that they end up calling clog's operator<<.
NB: I found it difficult to keep my question complete(**), minimal and verifiable all at the same time, so any suggestions/comments on that will be much appreciated. What matters most to me, though, is the approach I have taken rather than the specific bugs or implementation flaws.
class LogStream : public std::streambuf
{
public:
enum class Color { RED_BRIGHT, RED_DARK, /* ...others */ NO_COLOR };
LogStream(void);
LogStream(std::basic_ostream<char>& out, std::string cname, char c, Color icon_color, Color text_color = Color::NO_COLOR);
/* Non-copiable. */
LogStream(const LogStream&) = delete;
LogStream& operator=(const LogStream&) = delete;
static void setNameLength(int l);
protected:
int_type overflow(int_type c = traits_type::eof());
std::streamsize xsputn(const char* s, std::streamsize n);
private:
/* Important stuff: */
std::basic_ostream<char>& m_out;
bool m_new_line;
void conditionalPrintHeader(void);
void endLine(void);
/* For message decoration purposes: */
Color m_color_icon;
Color m_color_text;
char m_icon;
std::string m_cname;
static std::map<Color, const std::string> m_color_lut;
};
/* A macro to create static instances of a logger later in each CPP file. */
#define CREATE_LOGGER(klass) \
namespace Log { \
static std::ostream dbg(new LogStream( \
std::clog, \
#klass, \
'>', \
LogStream::Color::RED_BRIGHT, \
LogStream::Color::NO_COLOR)); \
static std::ostream err(new LogStream( \
std::clog, \
#klass, \
'e', \
LogStream::Color::RED_BRIGHT, \
LogStream::Color::RED_DARK)); \
}
My overridden functions are implemented like so:
std::streamsize LogStream::xsputn(const char* s, std::streamsize n)
{
conditionalPrintHeader();
if(s[n - 1] == '\n') {
m_new_line = true;
endLine();
}
m_out << s;
return n;
}
LogStream::int_type LogStream::overflow(int_type c)
{
if(c == traits_type::eof()) {
return traits_type::eof();
} else {
char_type ch = traits_type::to_char_type(c);
return xsputn(&ch, 1) == 1 ? c : traits_type::eof();
}
}
void LogStream::conditionalPrintHeader(void)
{
if(m_new_line) {
m_out << "... header and color escape codes ...";
m_new_line = false;
}
}
void LogStream::endLine(void)
{
m_out << "color escape code for no color.";
}
The functions conditionalPrintHeader and endLine essentially try to implement this basic structure:
[header string] [ANSI color code] [<the log message>] [end color code]
So that when I do:
Log::warn << "Integer: " << 123 << ", Bool: " << std::boolalpha << true << ", Float: " << 3.1415f << "\n";
The terminal outputs:
HEADER + [START COLOR] Integer: 123, Bool: true, Float: 3.1415 [END COLOR]
Most of the time everything works great except when I need to print integer values. Instead of the number, I get additional garbage, like so:
[ ... ] Integer: 123�~c, Bool: true, Float: 3.1415
Notes:
(*) Similar questions that inspired or directly contributed to my solution:
https://stackoverflow.com/a/10921803/1876268 --Where I took most of the implementation concept.
Add time stamp with std::cout
Correct way to declare/define custom cout-like object
https://codereview.stackexchange.com/a/187373/176115
Correct implementation of std::streambuf::overflow
(**) I pasted the whole header and source files in order to be as complete as possible and in case I'm missing the error somewhere else: Log.hpp, Log.cpp.
For now I considered that the problem laid in the character string argument of xsputn (which I assumed is not null-terminated). I solved my issue with integers like as follows, but I'm still unclear whether the approach is good or not.
std::streamsize LogStream::xsputn(const char* s, std::streamsize n)
{
conditionalPrintHeader();
if(s[n - 1] == '\n') {
m_new_line = true;
endLine();
}
std::string str;
for(int c = 0; c < n; c++) {
str += s[c];
}
m_out << str;
return n;
}

Order of decorations in Decorator Pattern

Most of you know the pizza / cofee example for the decorator pattern.
Pizza* pizza1 = BigPizzaDecorator(MushromDecorator(SimplePizza()));
Pizza* pizza2 = MushromDecorator(BigPizzaDecorator(SimplePizza()));
the two object behave in a similar way, but not completely, in particular if you have non-commutative operation, for example:
BigPizzaDecorator::price() { return 10 + PizzaDecorator::price(); } // this is commutative
BigPizzaDecorator::name() { return "big " + PizzaDecorator::name(); } // this is not commutative
So the price for pizza1 and pizza2 are the same, but the name is not, for example the first should be "Big mushroom pizza", the second "Mushroom big pizza". The first is english correct (probably better would be "Big pizza with mushroom", but it's not so important).
The book "Head first" point out this problem with the Cofee example:
When you need to peek at multiple layers into the decorator chain, you
are starting to push the decorator beyond its true intent.
Nevertheless, such things are possible. Imagine a CondimentPrettyPrint
decorator that parses the final decription and can print “Mocha, Whip,
Mocha” as “Whip, Double Mocha.”
what is the best way to do that? (operator< ?)
Ive never known this sort of thing to be needed when using decorators. And I would think that if you need to do this, then you shouldn't be using decorators, especially as you're knowingly "pushing the decorator beyond it's intent".
I have had a stab at doing this, the code is below. Basically, I create a thin layer around the SimplePizza object that understands what the decorators need, then the decorators decorate that.
The main problem here, is that to maintain order in the output, you would have to maintain a relationship between decorators - which can quickly become a maintenance nightmare.
#include <iostream>
#include <queue>
#include <sstream>
struct name_part
{
std::string mName;
int mPriority;
name_part(const std::string& name, int priority)
: mName(name)
, mPriority(priority)
{
}
};
bool operator<(const name_part& a, const name_part& b)
{
return (a.mPriority < b.mPriority);
}
std::string priority_queueToString(const std::priority_queue<name_part>& orig)
{
std::ostringstream oss;
std::priority_queue<name_part> q(orig);
while (!q.empty())
{
oss << q.top().mName << " ";
q.pop();
}
return oss.str();
}
struct SimplePizza
{
virtual std::string name()
{
return "pizza";
}
};
struct SimplePizzaImplementer : SimplePizza
{
SimplePizza *mDecorated;
SimplePizzaImplementer()
: mDecorated(0)
{
}
SimplePizzaImplementer(SimplePizza *decorated)
: mDecorated(decorated)
{
}
virtual std::string name()
{
return priority_queueToString(nameParts());
}
virtual std::priority_queue<name_part> nameParts()
{
std::priority_queue<name_part> q;
if (mDecorated)
{
q.push(name_part(mDecorated->name(), 0));
}
return q;
}
};
struct MushroomDecorator : SimplePizzaImplementer
{
SimplePizzaImplementer *mDecorated;
MushroomDecorator(SimplePizzaImplementer *decorated)
: mDecorated(decorated)
{
}
virtual std::string name()
{
return priority_queueToString(nameParts());
}
virtual std::priority_queue<name_part> nameParts()
{
std::priority_queue<name_part> q = mDecorated->nameParts();
q.push(name_part("mushroom", 1));
return q;
}
};
struct BigDecorator : SimplePizzaImplementer
{
SimplePizzaImplementer *mDecorated;
BigDecorator(SimplePizzaImplementer *decorated)
: mDecorated(decorated)
{
}
virtual std::string name()
{
return priority_queueToString(nameParts());
}
virtual std::priority_queue<name_part> nameParts()
{
std::priority_queue<name_part> q = mDecorated->nameParts();
q.push(name_part("big", 2));
return q;
}
};
int main()
{
SimplePizzaImplementer *impl = new SimplePizzaImplementer(new SimplePizza());
SimplePizza *pizza1 = new MushroomDecorator(new BigDecorator(impl));
SimplePizza *pizza2 = new BigDecorator(new MushroomDecorator(impl));
std::cout << pizza1->name() << std::endl;
std::cout << pizza2->name() << std::endl;
}
In terms of where to put such code, have an overloaded operator<< is feasible.
I feel that the "pushing the decorator beyond it's intent" really needs emphasis here.
Would you really build a serious application whose functioning depends on parsing
"Mocha, Whip, Mocha"
and formulating
"Whip, Double Mocha"
Conceptually you are inferring semantics from an interface that is not published with that intent. The result will be very brittle, minor changes in implementations of decorators: "Yummy super mocha special" would break the parser. Adding new decorators would require unknown levels of change.

What is good practice for generating verbose output?

what is good practice for generating verbose output? currently, i have a function
bool verbose;
int setVerbose(bool v)
{
errormsg = "";
verbose = v;
if (verbose == v)
return 0;
else
return -1;
}
and whenever i want to generate output, i do something like
if (debug)
std::cout << "deleting interp" << std::endl;
however, i don't think that's very elegant. so i wonder what would be a good way to implement this verbosity switch?
The simplest way is to create small class as follows(here is Unicode version, but you can easily change it to single-byte version):
#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;
enum log_level_t {
LOG_NOTHING,
LOG_CRITICAL,
LOG_ERROR,
LOG_WARNING,
LOG_INFO,
LOG_DEBUG
};
namespace log_impl {
class formatted_log_t {
public:
formatted_log_t( log_level_t level, const wchar_t* msg ) : fmt(msg), level(level) {}
~formatted_log_t() {
// GLOBAL_LEVEL is a global variable and could be changed at runtime
// Any customization could be here
if ( level <= GLOBAL_LEVEL ) wcout << level << L" " << fmt << endl;
}
template <typename T>
formatted_log_t& operator %(T value) {
fmt % value;
return *this;
}
protected:
log_level_t level;
boost::wformat fmt;
};
}//namespace log_impl
// Helper function. Class formatted_log_t will not be used directly.
template <log_level_t level>
log_impl::formatted_log_t log(const wchar_t* msg) {
return log_impl::formatted_log_t( level, msg );
}
Helper function log was made template to get nice call syntax. Then it could be used in the following way:
int main ()
{
// Log level is clearly separated from the log message
log<LOG_DEBUG>(L"TEST %3% %2% %1%") % 5 % 10 % L"privet";
return 0;
}
You could change verbosity level at runtime by changing global GLOBAL_LEVEL variable.
int threshold = 3;
class mystreambuf: public std::streambuf
{
};
mystreambuf nostreambuf;
std::ostream nocout(&nostreambuf);
#define log(x) ((x >= threshold)? std::cout : nocout)
int main()
{
log(1) << "No hello?" << std::endl; // Not printed on console, too low log level.
log(5) << "Hello world!" << std::endl; // Will print.
return 0;
}
You could use log4cpp
You can wrap your functionality in a class that supports the << operator which allows you to do something like
class Trace {
public:
enum { Enable, Disable } state;
// ...
operator<<(...)
};
Then you can do something like
trace << Trace::Enable;
trace << "deleting interp"
1. If you are using g++ you could use the -D flag, this allows the compilator to define a macro of your choice.
Defining the
For instance :
#ifdef DEBUG_FLAG
printf("My error message");
#endif
2. I agree this isn't elegant either, so to make it a bit nicer :
void verbose(const char * fmt, ... )
{
va_list args; /* Used as a pointer to the next variable argument. */
va_start( args, fmt ); /* Initialize the pointer to arguments. */
#ifdef DEBUG_FLAG
printf(fmt, &args);
#endif
/*This isn't tested, the point is to be able to pass args to
printf*/
}
That you could use like printf :
verbose("Error number %d\n",errorno);
3. A third solution easier, and more C++ and Unix like is to pass an argument to your program that is going to be used - as the macro earlier - to initialize a particular variable (that could be a global const).
Example :
$ ./myprogram -v
if(optarg('v')) static const verbose = 1;