9

I have need to print indented template names for debugging purposes. For example, instead of single-line, I would like to indent name like this:

boost::phoenix::actor<
    boost::phoenix::composite<
      boost::phoenix::less_eval,
      boost::fusion::vector<
        boost::phoenix::argument<0>,
        boost::phoenix::argument<1>,

I started writing my own but is getting to be complicated. Is there an existing solution?

if there is not one, can you help me to finish up my implementation? I will post it if so.

Thanks

this is what typeid.name looks like,

boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::less_eval, 
boost::fusion::vector<boost::phoenix::argument<0>, 
boost::phoenix::composite<boost::phoenix::multiplies_eval, 
boost::fusion::vector<boost::phoenix::argument<1>, boost::phoenix::argument<2>,
boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, 
boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, 
boost::fusion::void_, boost::fusion::void >, boost::fusion::void_, 
boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, 
boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, 
boost::fusion::void_> > >

this is my goal

 6 boost::phoenix::actor<
 7   boost::phoenix::composite<
 8     boost::phoenix::less_eval,
 9     boost::fusion::vector<
10       boost::phoenix::argument<0>,
11       boost::phoenix::composite<
12         boost::phoenix::multiplies_eval,
13         boost::fusion::vector<
14           boost::phoenix::argument<1>,
15           boost::phoenix::argument<2>,
16           boost::fusion::void_,
17           boost::fusion::void_,
18           boost::fusion::void_,
19           boost::fusion::void_,
20           boost::fusion::void_,
21           boost::fusion::void_,
22           boost::fusion::void_,
23           boost::fusion::void >, // indentation messed up
24           boost::fusion::void_,
25           boost::fusion::void_,
26           boost::fusion::void_,
27           boost::fusion::void_,
28           boost::fusion::void_,
29           boost::fusion::void_,
30           boost::fusion::void_,
31           boost::fusion::void_
32         >
33       >
34     >

so that I can actually read declaration

Anycorn
  • 50,217
  • 42
  • 167
  • 261
  • Where are these template names coming from that you're trying to print? Are you creating them yourself, or are parsing pre-existing input, or... The solution will depend not only on what you're trying to output, but also on where the input for this output comes from. – Jonathan M Davis May 21 '10 at 21:22
  • How does this post correlate with your answer below? – Thomas Matthews May 21 '10 at 21:43
  • 1
    It looks like he's trying to print out a stack trace. But he wants the template types to look nicer, so he's looking to replace them with versions that include extra spacing, including newlines. – Jonathan M Davis May 21 '10 at 22:21
  • I would argue that `boost::fusion::void_`, like `boost::mpl::na` are actually fillers (due to the lack of variadic templates) and do not logically pertain to the type so it would be better to actually remove them (and you would save some place too). – Matthieu M. May 22 '10 at 12:47

3 Answers3

6

How about, copy to clipboard, then

$ xclip -o | clang-format

For example, this takes the OP's template to

boost::phoenix::actor <
boost::phoenix::composite<
    boost::phoenix::less_eval,
    boost::fusion::vector<
    boost::phoenix::argument<0>,
    boost::phoenix::composite<
        boost::phoenix::multiplies_eval,
        boost::fusion::vector<
        boost::phoenix::argument<1>, boost::phoenix::argument<2>,
        boost::fusion::void_, boost::fusion::void_,
        boost::fusion::void_, boost::fusion::void_,
        boost::fusion::void_, boost::fusion::void_,
        boost::fusion::void_, boost::fusion::void>,
        boost::fusion::void_, boost::fusion::void_,
        boost::fusion::void_, boost::fusion::void_,
        boost::fusion::void_, boost::fusion::void_,
        boost::fusion::void_, boost::fusion::void_> > >

Not ideal, because there's an error somewhere in it. But it makes it pretty easy to find the error (the extra > after the void in the middle should be moved to the end). If we fix it, we get

boost::phoenix::actor<boost::phoenix::composite<
    boost::phoenix::less_eval,
    boost::fusion::vector<
        boost::phoenix::argument<0>,
        boost::phoenix::composite<
            boost::phoenix::multiplies_eval,
            boost::fusion::vector<
                boost::phoenix::argument<1>, boost::phoenix::argument<2>,
                boost::fusion::void_, boost::fusion::void_,
                boost::fusion::void_, boost::fusion::void_,
                boost::fusion::void_, boost::fusion::void_,
                boost::fusion::void_, boost::fusion::void, boost::fusion::void_,
                boost::fusion::void_, boost::fusion::void_,
                boost::fusion::void_, boost::fusion::void_,
                boost::fusion::void_, boost::fusion::void_,
                boost::fusion::void_>>>>>
Justin L.
  • 3,957
  • 3
  • 31
  • 29
2

minor adjustment of gf program, mainly not to split short templates

#ifndef PRETTY_NAME_HPP
#define PRETTY_NAME_HPP

#include <typeinfo>
#include <string>
#include <iostream>
#include <cxxabi.h>

#define TYPENAME(TYPE) typeid_name(typeid(TYPE).name())

std::string indent(std::string str, const std::string &indent = "  ") {
    std::string indent_ = std::string("\n");
    size_t token = 0;

    bool one_line = false;
    while ((token = str.find_first_of("<>,", token)) != std::string::npos) {
        size_t size = str.size();
        size_t close, open, comma;

        switch(str[token]) {
        case '<':
            close = str.find(">", token+1);
            open = str.find("<", token+1);
            comma = str.find(",", token+1);
            one_line = !(close > open) && !(comma < close);

            if (one_line) break;
            indent_.append(indent);

        case ',':
            str.insert(token + 1, indent_);
            break;

        case '>':
            if (!one_line) {
                indent_.erase(indent_.size() - indent.size());
                str.insert(token, indent_);
            }
            one_line = false;
        }

        token += 1 + str.size() - size;

        const size_t nw = str.find_first_not_of(" ", token);
        if(nw != std::string::npos) {
            str.erase(token, nw-token);
        }
    }

    return str;
}
std::string typeid_name(const char* name) {
// #ifdef HAVE_CXA_DEMANGLE
    size_t size;
    int status;
    char *buf = abi::__cxa_demangle(name, NULL, &size, &status);
    if (status  != 0) throw status;
    std::string string(buf);
    free(buf);
    return indent(string);
// #else
//     return name;
// #endif
}

#endif /* PRETTY_NAME_HPP */
Anycorn
  • 50,217
  • 42
  • 167
  • 261
1

Certainly not the most elegant piece, but this should get you going regarding the closing tags:

std::string indent(std::string str, const std::string &indent = "  ") {
    std::string indent_ = std::string("\n");
    size_t token = 0;

    while ((token = str.find_first_of("<>,", token)) != std::string::npos) {
        switch(str[token]) {
            case '<': indent_.append(indent);
            case ',': str.insert(token + 1, indent_);
                      break;
            case '>': indent_.erase(indent_.size() - indent.size());
                      str.insert(token, indent_);
        }

        token += indent_.size() + 1;            
        const size_t nw = str.find_first_not_of(" ", token);
        if(nw != std::string::npos) {
            str.erase(token, nw-token);
        }
    }

    return str;
}
Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236