#include <bits/stdc++.h>
using namespace std;
#define __deb(X...) (cout << "[" << #X << "]:" << X)
template <typename... type>
void debug(type &&... args)
{
((__deb(args)), ...);
}
int main()
{
int a = 1, b = 3;
debug(a,b);
return 0;
}
I got output like [args]:1[args]:3 but I wanted output like [a]:1[b]:3
One way could be to quote all the macro arguments using #__VA_ARGS__
and parse that string in the C++ function.
Example:
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
template<typename T, typename... Args>
std::string debug_detail(const char* names, T&& var, Args&&... args) {
std::ostringstream builder;
// find variable end
const char* end = names;
while(*end != ',' && *end != '\0') ++end;
// display one variable
(builder << ' ').write(names, end - names) << '=' << var;
// continue parsing?
if constexpr(sizeof...(Args) > 0) {
// recursively call debug_detail() with the new beginning for names
builder << debug_detail(end + 1, std::forward<Args>(args)...);
}
return builder.str();
}
template<typename... Args>
void debug_entry(const char* file, int line, const char* func,
const char* names, Args&&... args) {
std::ostringstream retval;
// common debug info
retval << file << '(' << line << ") " << func << ':';
// add variable info
retval << debug_detail(names, std::forward<Args>(args)...) << '\n';
std::cout << retval.str();
}
// the actual debug macro
#define debug(...) \
debug_entry(__FILE__,__LINE__,__func__,#__VA_ARGS__,__VA_ARGS__)
int main() {
int foo = 1;
const double bar = 2;
const std::string Hello = "world";
debug(foo,bar,Hello);
}
Possible output:
example.cpp(49) main: foo=1 bar=2 Hello=world
Demo
A C++20 version using std::source_location
:
#include <source_location>
template<typename... Args>
void debug_entry(const std::source_location location,
const char* names, Args&&... args) {
std::ostringstream retval;
// common debug info
retval << location.file_name() << '(' << location.line() << ','
<< location.column() << ") " << location.function_name() << ':';
// add variable info
retval << debug_detail(names, std::forward<Args>(args)...) << '\n';
std::cout << retval.str();
}
// the actual debug macro
#define debug(...) \
debug_entry(std::source_location::current(), #__VA_ARGS__,__VA_ARGS__)
Demo
Here's my humble attempt, which uses a macro FOO
to create a pair of the variable name and its value, and passes the arguments to a variadic function:
#include <utility>
#include <iostream>
#define FOO(var) std::make_pair(std::string(#var), var)
template <typename T>
void __deb(std::pair<std::string, T> arg) { std::cout << "[" << arg.first << "]:" << arg.second; }
template <typename... type>
void debug(std::pair<std::string, type> &&... args)
{
(__deb(args), ...);
}
int main()
{
int a = 1, b = 3;
debug(FOO(a), FOO(b));
}
Demo
Alternatively, to avoid having a macro call FOO
for each variable in debug
, you could define debug
as a macro that accepts #__VA_ARGS__
(string of arguments) and __VA_ARGS__
(argument values). Then parse each variable name and value:
#include <iostream>
#include <sstream>
#include <stdio.h>
#define debug(...) debug_print(#__VA_ARGS__,__VA_ARGS__)
template <typename T>
void __deb(std::istringstream &ss, T arg)
{
//Extract name from stream
std::string name;
std::getline(ss, name, ',');
//trim leading space
const auto pos(name.find_first_not_of(" "));
name.erase(0, pos);
std::cout << "[" << name << "]:" << arg;
}
template <typename... type>
void debug_print(const char* names, type&&...args)
{
std::istringstream ss(names);
(__deb(ss, args), ...);
}
int main()
{
int a = 1, b = 3, c = 4;
debug(a, b, c);
}
Demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With