C / C ++可以在marco中使用“ for loop”而不是“ do while”吗?

时间:2019-12-11 14:24:59

标签: c++ macros

假设“ cond”与程序中的任何名称都不冲突,以下两个构造是否等效?

#define DOWHILE do { (some_code); } while (0)

#define FORLOOP for(bool cond = true; cond; cond = false) (some_code)

这个问题的目的是:

我有这样的东西

bool printLogs; // nonconstant dynamic variable

我有一个宏(我无法做大的改变,这是一个大项目;我必须处理这个宏)#define LOG ... 就像

LOG << "message" << 1 << 0.5 << 'a';

我希望这个宏变成

if (printLogs) {
    PrinterClass() << "message" << 1 << 0.5 << 'a';
}

因此,如果不打印,则不计算打印参数。在这种情况下,我的解决方法是

#define LOG for(cond = printLogs; cond; cond = false) PrinterClass()

此解决方案正确吗?还有其他方法吗?

更新:很明显,您不能在此处使用简单的if。例如,此代码将无效

#define LOG if(printLogs) PrinterClass()

int main() {
    if (1)
        LOG << 1;
    else
        LOG << 2;
}

更新2:我希望看到有关我或您的解决方案正确性的说明。我必须确保该解决方案不会引起任何问题。您可以在代码中可以插入语句的任何位置插入“ do while”构造。因此,“ do while”的行为很简单。这对我的建筑是真的吗?

更新3:带有全局对象的解决方案不能令人满意,因为它将导致巨大的开销

#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;
}

所有优化都将变为

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);
    }
}

因此,对于<<的每次使用,您都具有原子比较。参见https://godbolt.org/z/sEoUCw

2 个答案:

答案 0 :(得分:2)

您可以这样做:

#define LOG if (!printLogs){} else PrinterClass()

答案 1 :(得分:0)

如果您想要一个没有多个检查开销的面向对象的解决方案,请考虑以下内容:

#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; }