我发布了this的答案。代码:
#include <atomic>
#include <utility>
void printImpl(...);
std::atomic<bool> printLog = false;
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; }
本质上,代码要么忽略所有数据,要么记录所有数据。这个想法是将 atomic<bool>
记录在一个普通的 bool
中,以便更容易地进行优化。我认为大多数编译器可以轻松地优化掉 if (active)
部分,因为它在调用之间没有改变的方式。结果发现,大多数编译器确实内联了对 unchecked_log::operator<<
函数的调用,但并未优化掉分支。是否有什么东西阻止了这种优化?这样做是否合法?
Log::operator <<
依赖于全局变量printLog
。如果你真的不能改变它,编译器会期望使用常量。而且这是同一个ulog
对象,我认为标准可能会禁止ulog::operator <<
的这种“优化”,例如如果有两个线程怎么办? - Fire Lancer