Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a fully-qualified function name in C++ (gcc), _excluding_ the return type?

Tags:

c++

gcc

This question describes how to use __PRETTY_FUNCTION__ to get a full name of a function, including its return type, argument types, namespace and template parameters.

Consider the following, beautiful function:

namespace foo {
namespace {

template<int i>
int (*bar(int (*arg)(int *)))(int *) {
    printf("%s\n", __PRETTY_FUNCTION__);

    return arg;
}

} // anonymous namespace
} // namespace foo

If it's not obvious to you, the function takes, and returns, a pointer to an int * -> int function.

Its pretty name is, when compiled with g++ (4.9),

int (* foo::{anonymous}::bar(int (*)(int*)))(int*) [with int i = 1337]

and, with clang++ (3.5),

int (*foo::(anonymous namespace)::bar(int (*)(int *)) [i = 1337])(int *)

Those strings are pretty unsuitable for testing whether the function is part of a certain namespace. Is there any other way, or, say, a compiler-provided library to parse those strings?

To clarify, I'd rather have something like

foo::{anonymous}::bar <I don't care about anything beyond this point>

Even more ideally, I'd like a compile-time way, such as a constexpr function split(__PRETTY_FUNCTION__) that yields some sort of list of

  • fully qualified function name
  • return type
  • type of arg0
  • type of arg1

etc, but I'd be happy with just the fully-qualified function name.

like image 760
mic_e Avatar asked Nov 11 '14 18:11

mic_e


1 Answers

After a more careful observation I wrote this code:

template <typename InputIterator, typename T>
InputIterator findClosing( InputIterator first, InputIterator last, T close )
{
    if (first == last)
        return last;

    auto open = *first;
    unsigned counter = 1;
    while (++first != last)
    {
        if (*first == close && --counter == 0)
            return first;
        if (*first == open)
            ++counter;
    }

    return last;
}

template <std::size_t N,
          std::size_t N2>
std::string f(char const(&str)[N], char const(&name)[N2])
{
    using namespace std;

    // Argument to isalnum must be unsigned:
    auto cond = [] (unsigned char c) {return !isalnum(c) && c != '_';};

    auto iter = str;
    for (;;++iter)
    {
        iter = search( iter, end(str),
                       begin(name), end(name)-1 );

        if (iter == end(str))
            throw invalid_argument("");

        if ((iter == begin(str)      || cond(iter[-1]))
         && (iter ==   end(str) - N2 || (cond(iter[N2-1]) && iter[N2-1] != ':')))
            break;
    }

    auto origin_iter = iter;
    while(iter != begin(str))
    {
        --iter;
        for (auto p : {"()", "{}"})
        if (*iter == p[1])
            iter = findClosing(reverse_iterator<char const*>(iter+1),
                               reverse_iterator<char const*>(begin(str)),
                               p[0]).base()-2;

        if (cond(*iter) && *iter != ':')
            return string(iter+1, origin_iter+N2-1);
    }

    return string(iter, origin_iter+N2-1);
}

It should work with any function, assuming no unnecessary whitespace is existent in __PRETTY_FUNCTION__ and __func__ contains solely the unqualified function name.

Demo.

like image 144
Columbo Avatar answered Oct 08 '22 16:10

Columbo