Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you create a macro (or other tool) that uses the text of given variables in string format?

Tags:

c++

macros

I'm a fan of debug printing when trying to investigate problems in my code:

cout << "foo:" << foo << "bar:" << bar << "baz:" << baz;

Since I write code like this very often, it would be awesome if I could make it generic and easier to type. Maybe something like this:

DEBUG_MACRO(foo, bar, baz);

Even though foo, bar, and baz resolve to variable names, not strings, is it possible to use their variable names to create the strings "foo:", "bar:", and "baz:"? Can you write a function or macro that takes an unspecified number of parameters?

like image 737
Cory Klein Avatar asked Jun 05 '12 15:06

Cory Klein


1 Answers

If you have C++11 you can do something typesafe and fairly neat with variadic templates, e.g.:

#include <string>
#include <iostream>

template <typename T>
void debug(const T& v) {
  std::cout << v << "\n";
}

template <typename T, typename... Tail>
void debug(const T& v, const Tail& ...args) {
  std::cout << v << " ";
  debug(args...);
}

#define NVP(x) #x":", (x)

int main() {
  int foo=0;
  double bar=0.1;
  std::string f="str";
  debug(NVP(foo),NVP(bar),NVP(f));
}

The NVP macro here is entirely optional and only needed if you want to print the name you referred to it by in the code as well.

If you really want to skip the NVP bit you can use the Boost pre-processor library (or roll your own) e.g.:

#include <string>
#include <iostream>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>

template <typename T>
void debug_impl(const T& v) {
  std::cout << v << "\n";
}

template <typename T, typename... Tail>
void debug_impl(const T& v, const Tail& ...args) {
  std::cout << v << " ";
  debug_impl(args...);
}

#define NVP(x) #x":", (x)
#define MEMBER( r, data, i, elem ) BOOST_PP_COMMA_IF( i ) NVP(elem)

#define debug( members )                                \
  debug_impl(                                           \
  BOOST_PP_SEQ_FOR_EACH_I( MEMBER,, members )           \
  )


int main() {
  int foo=0;
  double bar=0.1;
  std::string f="str";
  debug((foo)(bar)(f));
}

for the price of some slightly odd syntax. My example is based on this answer. I tried to use variadic macros to solve this directly as a "pure" C++11 solution, but it turns out recursing through a list is trickier than you'd hope with it.

like image 158
Flexo Avatar answered Sep 29 '22 06:09

Flexo