15

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 clarified variadic macros after searching around for the answer.

Conceptual Example:

#include <iostream>
#define LOG(...) std::cout << ... << ... << std::endl
int main() {
    LOG("example","output","filler","text");
    return 0;
}

would output:

exampleoutputfillertext
a3f
  • 8,517
  • 1
  • 41
  • 46
BlurryZombie
  • 167
  • 1
  • 1
  • 8

4 Answers4

35

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++.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
  • 1
    Okay! Thanks for the advice. The code it quite brilliant :-) – BlurryZombie Mar 29 '15 at 07:49
  • 1
    @BlurryZombie You're welcome. The code is entirely commonplace. You just need to learn about the features I mentioned. – Mike Kinghan Mar 29 '15 at 07:53
  • thanks, but it would be nice to have the \n added automatically – jokoon Nov 14 '19 at 10:34
  • @jokoon I was able to get the \n added automatically in the c++11/14 version by updating "void log(){}" to "void log(){std::cout << std::endl;}" – Eliott Mar 10 '20 at 02:26
  • Also, I wish I could have a version, without cout, meaning something that concatenate several strings into one. – jokoon Apr 21 '20 at 07:46
  • @jokoon iirc you can replace the destination with a stringstream (instead of cout), and concatenate several strings into one, albeit using an intermediate stringstream variable. – Razzle Jan 18 '21 at 13:37
14

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.

CygnusX1
  • 20,968
  • 5
  • 65
  • 109
3

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");
}
vsoftco
  • 55,410
  • 12
  • 139
  • 252
-2

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 
Equation Solver
  • 545
  • 7
  • 18