如何在C ++(gcc)中获取完全限定的函数名,_excluding_返回类型?

时间:2014-11-11 18:14:57

标签: c++ gcc

This question描述了如何使用__PRETTY_FUNCTION__获取函数的全名,包括其返回类型,参数类型,命名空间和模板参数。

考虑以下,美丽的功能:

namespace foo {
namespace {

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

    return arg;
}

} // anonymous namespace
} // namespace foo

如果您不明白,该函数将获取并返回指向int * - &gt;的指针。 int功能。

当使用g++(4.9)编译时,其漂亮的名称是

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

clang++(3.5),

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

这些字符串非常不适合测试函数是否属于某个命名空间。有没有其他方法,或者说,编译器提供的库来解析这些字符串?

为了澄清,我宁愿拥有像

这样的东西
foo::{anonymous}::bar <I don't care about anything beyond this point>

更理想的情况是,我喜欢编译时的方式,例如constexpr函数split(__PRETTY_FUNCTION__),它会产生某种列表

  • 完全限定的功能名称
  • 返回类型
  • 类型为arg0
  • arg1的类型

等,但我对完全合格的功能名称感到满意。

2 个答案:

答案 0 :(得分:4)

经过仔细观察,我写了这段代码:

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);
}

它应该适用于任何函数,假设__PRETTY_FUNCTION__中不存在不必要的空格,__func__仅包含非限定函数名。

Demo

答案 1 :(得分:3)

这并不是你所要求的,因为它没有返回一个constexpr字符串的值,但是它接近了。但是,它完全是constexpr,它返回一个指向命名空间开头的指针,以及指向它结尾的指针(函数名的开头),以及可选的字符串长度。 / p>

constexpr bool isNotIdentifierChar(const char *pf)
{
    return !isalnum(*pf) && *pf!='_';
}

constexpr const char* getNamespaceEnd(const char *pf, const char *func)
{
    return (isNotIdentifierChar(pf) && 0==strncmp(&pf[1], func, strlen(func))
    && isNotIdentifierChar(pf+strlen(func)+1) && ':'!=pf[strlen(func)+1])  
        ? &pf[1] 
        : getNamespaceEnd(++pf, func);
}

constexpr const char* getNamespaceStartIter(const char *pf, const char *end)
{
    return (*pf==' ' && strchr(&pf[1], ' ') > end) 
        ? &pf[1] 
        : getNamespaceStartIter(++pf, end);
}

constexpr const char* getNamespaceStart(const char *pf, const char *func)
{
    return getNamespaceStartIter(pf, getNamespaceEnd(pf, func));
}

constexpr size_t getNamespaceSize(const char *pf, const char *func)
{
    return getNamespaceEnd(pf, func) - getNamespaceStart(pf, func);
}

一个人不能constexpr返回std::string因为std::string(或任何等效的构造)有一个非平凡的析构函数,但我们可以返回开始和结束像这样的命名空间:

printf("%s\n", std::string(
        getNamespaceStart(__PRETTY_FUNCTION__, __func__),
        getNamespaceEnd(__PRETTY_FUNCTION__, __func__)+strlen(__func__)
    ).data());

此版本包含功能名称(本例中为“bar”),但也可以省略+strlen(__func__)

我们也可以通过使用一个简单的类来使它更清晰:

class NamespaceString {
public:
    NamespaceString(const char *pf, const char *func) 
        : start(getNamespaceStart(pf, func)),
          end(getNamespaceEnd(pf, func)) {}
    std::string getString() const {
        return std::string(start, end);
    }
private:
    const char *start;
    const char *end;
};

然后在函数中使用更清晰:

static const NamespaceString ns(__PRETTY_FUNCTION__, __func__);
printf("%s\n", ns.getString().data());

更新了演示,其中包括@ Columbo的答案和这一个:live code