问题
Are the two below constructions equivalent in assumption that "cond" is not conflicting with any name in the program
#define DOWHILE do { (some_code); } while (0)
#define FORLOOP for(bool cond = true; cond; cond = false) (some_code)
The purpose of this question is:
I have something like this
bool printLogs; // nonconstant dynamic variable
And I have a macro(I cannot do big changes, it is a big project; I have to deal with this macro) #define LOG ...
which is used like
LOG << "message" << 1 << 0.5 << 'a';
And I want this macro to turn into
if (printLogs) {
PrinterClass() << "message" << 1 << 0.5 << 'a';
}
So the printed arguments are not calculated if not printed. In this case my solution is
#define LOG for(cond = printLogs; cond; cond = false) PrinterClass()
Is this solution correct? Are there any other ways?
UPDATE: Obviouse you cannot use a simple if
here. For example this code won't work
#define LOG if(printLogs) PrinterClass()
int main() {
if (1)
LOG << 1;
else
LOG << 2;
}
UPDATE 2: I expect to see the explanation of the correctness of my or your solution. I must be sure that solution would not cause any problems. You can insert the "do while" construction anywhere in your code where you can insert a statement. So "do while" behaves as a simple statement. Is that true for my construction?
UPDATE 3: The solution with global object does not satisfy as it will cause a huge overhead
#include <atomic>
void printImpl(...);
std::atomic<bool> printLog;
struct Log {
template <typename T>
Log& operator<<(const T& t) {
if (printLog) {
printImpl(t);
}
return *this;
}
};
int main() {
Log() << 1 << 2;
}
After all optimizations will turn into
int main() {
if (printLog) {
printImpl(1);
}
// Still should check because printImpl could have changed this variable.
// C++ does not provide any way to say "I promise it won't change printLog"
if (printLog) {
printImpl(2);
}
}
So you have atomic comparison for each use of <<. See https://godbolt.org/z/sEoUCw
回答1:
You can do it like this:
#define LOG if (!printLogs){} else PrinterClass()
回答2:
If you want an object-oriented solution without the overhead of multiple checks, consider something like this:
#include <atomic>
#include <utility>
void printImpl(...);
std::atomic<bool> printLog;
class Log {
public:
template <typename T>
const auto& operator<<(T&& t) {
if (printLog) {
ulog.active = true;
return ulog << std::forward<T>(t);
} else {
ulog.active = false;
return ulog;
}
}
private:
struct unchecked_log {
template <typename T>
const auto& operator<<(T&& t) const {
if (active) {
printImpl(std::forward<T>(t));
}
return *this;
}
bool active{false};
};
unchecked_log ulog{};
};
// Instead of the macro. Doesn't break backward compatibility
Log LOG;
void test(bool) { LOG << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10; }
来源:https://stackoverflow.com/questions/59287937/c-c-can-for-loop-be-used-in-a-marco-instead-of-do-while