Reputation: 33
During development of my project in C++
I have a frequent need of debugging and I usually use this macro to do it
#define DBUG(a) {std::cout << #a << " : " << a << std::endl;};
But many times I need to do something like this
int a;
std :: string b;
double c;
...
...
DBG(a); DBG(b); DBG(c);
But ideally it might be possible to just write DBUG(a, b, c)
or DBG(a, b, c, d, e)
for more variables to achieve something like this. After some research this looked like a problem in meta-programming or more specifically code-generation, but because of my limited knowledge in these areas I could not find a way to go about it.
If possible I would like to solve this without using Boost or other external libraries, and using the features in C++98
although if it is not possible I'm willing to use C++11
.
Upvotes: 3
Views: 666
Reputation: 860
you may use your own DBUG(a)
the following way
DBUG(a << " " << b << " " << c);
Upvotes: 0
Reputation: 154015
I don't like a limitation to a specific number of arguments. I didn't find a nice approach which decodes the name statically so the names are put together as a comma separated string and then decoded at run-time. Overall, that may be a bit too heavy-weight but, at least, it does as was asked and has not limitation on the number of arguments (other than compiler limitations, that is):
#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <tuple>
#include <vector>
#include <type_traits>
#include <stdlib.h>
template <int I, int S, typename... V>
typename std::enable_if<I == S>::type
debug_var(std::vector<std::string> const&, std::tuple<V...> const&)
{
}
template <int I, int S, typename... V>
typename std::enable_if<I != S>::type
debug_var(std::vector<std::string> const& n, std::tuple<V...> const& v)
{
std::cout << n[I] << '=' << std::get<I>(v) << ' ';
debug_var<I + 1, S>(n, v);
}
template <typename... V>
void debug(std::vector<std::string> const& n, std::tuple<V...> const& v)
{
debug_var<0, sizeof...(V)>(n, v);
std::cout << '\n' << std::flush;
}
std::vector<std::string> debug_names(char const* names)
{
std::vector<std::string> result;
std::istringstream in(names);
for (std::string name; std::getline(in >> std::ws, name, ','); ) {
result.push_back(name);
}
return result;
}
#define DEBUG(...) debug(debug_names(#__VA_ARGS__), std::tie(__VA_ARGS__));
int main()
{
int a=1, b=2;
DEBUG(a, b);
DEBUG();
}
The code uses several features which were introduced by the 2011 revision of C++.
Upvotes: 7
Reputation: 258
How about using some good ol' C++11 variadic templates?
#include <iostream>
#include <sstream>
#include <string>
template <typename T>
std::string make_string(const T& t)
{
std::ostringstream oss;
oss << t;
return oss.str();
}
template <typename Thead, typename ... Ttail>
std::string make_string(const Thead& head, const Ttail& ... tail)
{
return make_string(head) + make_string(tail...);
}
void debug(const std::string& msg)
{
std::cout << "DEBUG: " << msg << std::endl;
}
void debug(void)
{
std::cout << "DEBUG!" << std::endl;
}
template <typename ... Targs>
void debug(const Targs& ... args)
{
debug(make_string(args...));
}
int main(void)
{
int z;
debug("We're gonna crash: ", &z, "!");
debug();
debug(3.14);
}
Upvotes: -1
Reputation: 61970
Here's one solution adapted from this answer. You have to define your macros to support up to a maximum number of parameters by changing the CHOOSER
and DBG
macros, as well as adding appropriate DBG#
macros. It does require C++11, too.
#include <iostream>
#define DBG1(a) std::cout << #a ": " << a << "\n"
#define DBG2(a, b) DBG1(a); DBG1(b)
#define DBG3(a, b, c) DBG2(a, b); DBG1(c)
#define CHOOSER(a, b, c, CHOICE, ...) CHOICE
#define DBG(...) CHOOSER(__VA_ARGS__, DBG3, DBG2, DBG1)(__VA_ARGS__)
int main() {
int a{}, b{1}, c{5};
DBG(a, b, c);
}
Output:
a: 0
b: 1
c: 5
Upvotes: 4