C/C++ Can “for loop” be used in a marco instead of “do while”?

試著忘記壹切 提交于 2020-02-02 11:13:25

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!