-2

Is there a way to create an ostream instance which basically doesn't do anything and doesn't evaluate code ?

For example:

#include <iostream>

#if defined(DEBUG)
    #define LOG std::cout
#else
    #define LOG std::ostream {nullptr}
#endif

#if defined(DEBUG)
std::string MyFunc()
{
    return "mystring";
}
#endif

int main()
{
    LOG << MyFunc() << std::endl;
    return 0;
}

If the flag "DEBUG" is set, the compilation works. Otherwise, I have the following error :

error: 'MyFunc' was not declared in this scope

Is it possible to skip code after null stream operator?

I found the following topic Standard no-op output stream

  • No, C++ function calls require all parameters to be evaluated... – fabian May 16 '23 at 15:13
  • If you're willing to change your syntax a bit something like [this](http://coliru.stacked-crooked.com/a/3b609029d205676f) could work. – Miles Budnek May 16 '23 at 15:18
  • two things to consider: a) you do not necessarily need 0 code, as long as the compiler can realize that the code does nothing any code is as good as 0 code. b) sometimes turning on or off debug logging should not change the execution too much. There are situations where you would want `MyFunc` to be called even without logging (either for side effects or merely for the time it takes to call it) – 463035818_is_not_an_ai May 16 '23 at 15:30
  • how is this question different from https://stackoverflow.com/questions/11826554/standard-no-op-output-stream/11826666#11826666 ? – 463035818_is_not_an_ai May 16 '23 at 16:09
  • or this https://stackoverflow.com/questions/11826554/standard-no-op-output-stream? – 463035818_is_not_an_ai May 16 '23 at 16:11

2 Answers2

2

No, it isn't possible.

LOG << MyFunc() << std::endl; is similar to operator<<(operator<<(LOG, MyFunc()), std::endl);. Even if operator<< doesn't do anything, it still can't prevent MyFunc() from being called.

You may use macro tricks instead. If you use LOG(MyFunc() << std::endl); it is trivial since you can make LOG(anything) disappear with #define LOG(...). It is also possible to #define LOG while(0) std::cout (while instead of if so that it doesn't mess up if the next like is else).

user253751
  • 57,427
  • 7
  • 48
  • 90
1

For one don't use macros in C++ unless you really have to. There is also no need to write a stream that does nothing. Using C++ and format library you can do this. In release mode this will compile to a function without side effects which can be optimized away totally.

Having said that : try to not add logging for debugging, use unit tests (design with interfaces + dependency injection) and just test that parts of your code work independently (that will avoid the need for a lot of logging).

#include <iostream>
#include <format>
#include <string_view>

// fmt is a standard std::format compatible format string
template<typename... args_t>
void Log(std::format_string<args_t...> fmt, args_t&&...args)
{
#ifdef _DEBUG
    std::cout << std::format(fmt, std::forward<args_t>(args...));
#endif
}

int main()
{
    Log("{},{}\n", "test", 42);
    return 0;
}
vitaut
  • 49,672
  • 25
  • 199
  • 336
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19