user2833292
user2833292

Reputation: 33

C++ Meta-programming

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

Answers (4)

aah134
aah134

Reputation: 860

you may use your own DBUG(a) the following way

DBUG(a << " " << b << " " << c);

Upvotes: 0

Dietmar K&#252;hl
Dietmar K&#252;hl

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

hauzer
hauzer

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

Qaz
Qaz

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

Related Questions