How to make a variadic macro for std::cout?

前端 未结 4 1142
北恋
北恋 2020-11-27 22:05

How would I make a macro that took a variable amount of arguments, and prints its out using std::cout? Sorry if this is a noob question, couldn\'t find anything that clarifi

相关标签:
4条回答
  • 2020-11-27 22:22

    You can try this one

    #include <iostream>
    
    #define LOG() std::cout
    
    int main()
    {
        LOG() << "Hello! " << "how " << "are " << "you " << std::endl;
        return 0;
    }
    

    Output:

    Hello!  how are  you 
    
    0 讨论(0)
  • 2020-11-27 22:23

    Not sure there is any way of defining a variadic macro in C++ (at least, not a portable way). Why don't you use a variadic template approach? Something like

    #include <iostream>
    
    void LOG() {}
    
    template<typename Head, typename... Args>
    void LOG(const Head& head, const Args&... args )
    {
        std::cout << head << " ";
        LOG(args...);
    }
    
    int main()
    {
        LOG("This", "is" , "the", 3, "rd test");
    }
    
    0 讨论(0)
  • 2020-11-27 22:29

    You do not need preprocessor macros to do this. You can write it in ordinary C++. In C++11/14:

    #include <iostream>
    #include <utility>
    
    void log(){}
    
    template<typename First, typename ...Rest>
    void log(First && first, Rest && ...rest)
    {
        std::cout << std::forward<First>(first);
        log(std::forward<Rest>(rest)...);
    }
    
    int main()
    {
        log("Hello", "brave","new","world!\n");
        log("1", 2,std::string("3"),4.0,'\n');
    }
    

    Live demo

    In C++17:

    template<typename ...Args>
    void log(Args && ...args)
    {
        (std::cout << ... << args);
    }
    

    is all it takes. Live demo

    Output:

    Hellobravenewworld!
    1234
    

    Research variadic templates, parameter packs and fold expressions rather than variadic macros, which are rarely useful in modern C++.

    0 讨论(0)
  • 2020-11-27 22:31

    When using variadic macros you need __VA_ARGS__ to expand all the arguments. The problem however is that those arguments are comma-separated. Presumabely it just separates arguments to a function call, but since macros works with just text you can actually use __VA_ARGS__ in other contexts as well, where a comma-separated list makes sense.

    The trick you can employ is to define your own comma operator for std::ostream (the type of std::cout). For example:

    #include<iostream>
    #define LOG(...) std::cout , __VA_ARGS__ , std::endl
    
    template <typename T>
    std::ostream& operator,(std::ostream& out, const T& t) {
      out << t;
      return out;
    }
    
    //overloaded version to handle all those special std::endl and others...
    std::ostream& operator,(std::ostream& out, std::ostream&(*f)(std::ostream&)) {
      out << f;
      return out;
    }
    
    int main() {
      LOG("example","output","filler","text");
      return 0;
    }
    

    Now, the LOG invocation will expand to:

    std::cout , "example" , "output" , "filler" , "text" , std::endl;
    

    and the commas will invoke the overloaded comma operators.

    If you don't like overloaded operator, polluting all std::ostream-s, you can encapsulate std::cout with your own special logger class.

    0 讨论(0)
提交回复
热议问题