宏获取最新的命名空间和函数名(而不是完整的签名)? [英] Macro to obtain current namespace and function name (but not full signature)?

查看:161
本文介绍了宏获取最新的命名空间和函数名(而不是完整的签名)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有获得当前的命名空间和功能名称的C ++宏?例如:

 命名空间富{
  命名空间吧{
    无效巴兹(INT I,双D){
      性病::法院LT&;<万家乐<<的std :: ENDL;
    }
  }
}

将打印 :: foo的酒吧::巴兹。我知道的__ __功能,但它不给的命名空间。和 BOOST_CURRENT_FUNCTION 给整个签名,含。参数和返回值类型:

 无效美孚::酒吧::巴兹(INT,双)

也许,它是可以编写提取从 BOOST_CURRENT_FUNCTION 命名空间和函数名的宏?

我想,对于日志记录,得到一个记录字符串像

  :: foo的酒吧::巴兹 - 嗒嗒日志消息等等


解决方案

据我所知,这是不可能的(可移植没有)。然而,从完整的签名就可以的提取物的这些参数。当然,这需要分析说,签名......这不是那么容易:X

下面是我目前使用的功能:

  //我们想消费什么:
//无效
//符号短
//无符号整型
//测试::酒吧< T,N>
//
静态字符常量* consumeType(字符常量* const的开始,字符常量* const的结束){
  静态常量StringRef签名(签名);
  静态常量StringRef无符号(符号);  字符常量* IT =开始;  如果(startsWith(它,签名)){这+ = Signed.size()+ 1; }
  否则,如果(startsWith(它,无符号)){这+ = Unsigned.size()+ 1; }  //跳过的返回类型
  为size_t templateNest = 0;
  而(它!=结束){
    如果(*它==''和templateNest == 0){打破; }
    如果(*它=='<'){++ templateNest; }
    如果(*它=='>'和templateNest大于0){--templateNest; }    ++它;
  }  把它返还;
} // consumeType//
// \\参数签名:签名通过GCC __func___返回
// \\回报:全名,包括名字空间限定符和类(如果有的话)
//
//无效的Test ::酒吧< T,N> ::参数(U)常量
// [与unsigned int类型O = 4U,U =测试::美孚,
// T =测试::富,无符号整型N = 3U]
// - >测试::酒吧< T,N> ::参数
//
StringRef parseFunctionName(StringRef const的签名){
  字符常量*开始= signature.begin();
  字符常量*结束= signature.end();  //跃过返回类型
  开始= consumeType(开始,结束);
  如果(开始==结束){返回签名; }  //返回类型之后跳过空间
  ++开始;
  如果(开始==结束){返回签名; }  //如果我们遇到一个'('那么就意味着我们返回的函数,
  //我们再次需要跳过的返回类型
  如果(*开始=='('){
    开始= consumeType(++开始,结束);    //跳过空间
    ++开始;
    如果(开始==结束){返回签名; }
  }  //最后,我们得到的开始,我们需要得到结束,这是
  //第一开口(
  字符常量* E =的std ::找到(开始,结束,'(');
  返回StringRef(开始,电子 - 开始);
} // parseFunctionName

和其accompagnying测试:

 的#define UT_FUNCTION_CHECK(Signature_,名_)\\
  UT_CHECK(parseFunctionName(StringRef(Signature_))==名_);void函数(){
  //常规功能
  UT_FUNCTION_CHECK(INT主要(),主)
  UT_FUNCTION_CHECK(INT美孚(INT,双),富)
  UT_FUNCTION_CHECK(无符号整型美孚(INT,双),富)  //模板
  UT_FUNCTION_CHECK(unsigned int类型的Test ::酒吧< T,N> ::打印()const的
                    [和T =测试::富,无符号整型N = 3U],
                    测试::酒吧< T,N> ::打印)
  UT_FUNCTION_CHECK(测试::酒吧< T,N>的Test ::酒吧< T,N> ::打印()const的
                    [和T =测试::富,无符号整型N = 3U],
                    测试::酒吧< T,N> ::打印)
  UT_FUNCTION_CHECK(无效的Test ::酒吧< T,N> ::参数(U)常量
                    [与unsigned int类型O = 4U,U =测试::美孚
                    T =测试::富,无符号整型N = 3U],
                    测试::酒吧< T,N> ::参数)  //函数返回功能
  UT_FUNCTION_CHECK(无效(*测试::富:: FUNC()const的)(),
                    测试::富:: FUNC)
  UT_FUNCTION_CHECK(无效(测试::富:: *测试::富::方法()const的)(INT)善变,
                    测试::富::法)
  UT_FUNCTION_CHECK(无效(测试::富:: *测试::富::超())
                    (无效(测试::富:: *)(int)的挥发性)常量
                    测试::富::超级)
  } //功能

它的工作原理结合gcc的 __ __ FUNC 宏。

StringRef 类是类似的 LLVM :: StringRef

我想应该包括你的需要,如果你能负担得起额外的解析。这是相当快:无回溯,也没有动态分配,所以不应该是一个问题(特别是相对于写入文件...)

希望它帮助。

Is there a C++ macro that obtains the current namespace and function name? Example:

namespace foo {
  namespace bar {
    void baz(int i, double d) {
      std::cout << MACRO << std::endl;
    }
  }
}

would print foo::bar::baz. I know of __FUNCTION__ but it doesn't give the namespace. And BOOST_CURRENT_FUNCTION gives the whole signature, incl. arguments and return type:

void foo::bar::baz(int, double)

Maybe, is it possible to write a macro that extracts the namespace and function name from BOOST_CURRENT_FUNCTION?

I want that for logging purposes, to get a logging string like

foo::bar::baz -- blah logging message blah

解决方案

As far as I know, it's not possible (not portably). However from the full signature you can extract those arguments. Of course it requires parsing said signature... which is not so easy :x

Here is the function I use at the moment:

// What we want to consume:
//  void
//  signed short
//  unsigned int
//  Test::Bar<T, N>
//
static char const* consumeType(char const* const begin, char const* const end){
  static StringRef const Signed("signed");
  static StringRef const Unsigned("unsigned");

  char const* it = begin;

  if (startsWith(it, Signed)) { it += Signed.size() + 1; }
  else if (startsWith(it, Unsigned)) { it += Unsigned.size() + 1; }

  // jump over the return type
  size_t templateNest = 0;
  while (it != end) {
    if (*it == ' ' and templateNest == 0) { break; }
    if (*it == '<') { ++templateNest; }
    if (*it == '>' and templateNest > 0) { --templateNest; }

    ++it;
  }

  return it;
} // consumeType

//
// \param signature: signature as returned by __func___ on gcc
// \return: full name, included namespace qualifier and class (if any)
//
// void Test::Bar<T, N>::parameterized(U) const
//   [with unsigned int O = 4u, U = Test::Foo,
//    T = Test::Foo, unsigned int N = 3u]
//    -> Test::Bar<T, N>::parameterized
//
StringRef parseFunctionName(StringRef const signature) {
  char const* begin = signature.begin();
  char const* end = signature.end();

  // Jump over the return type
  begin = consumeType(begin, end);
  if (begin == end) { return signature; }

  // skip the space right after the return type
  ++begin;
  if (begin == end) { return signature; }

  // if we encounter a '(' then it means that we return a function,
  // and we once again need to jump over the return type
  if (*begin == '(') {
    begin = consumeType(++begin, end);

    // skip the space
    ++begin;
    if (begin == end) { return signature; }
  }

  // and finally, we got the beginning, and we need to get the end, which is
  // the first opening '('
  char const* e = std::find(begin, end, '(');
  return StringRef(begin, e - begin);
} // parseFunctionName

And its accompagnying tests:

#define UT_FUNCTION_CHECK(Signature_, Name_) \
  UT_CHECK(parseFunctionName(StringRef(Signature_)) == Name_);

void Function() {
  // Regular functions
  UT_FUNCTION_CHECK("int main()", "main")
  UT_FUNCTION_CHECK("int foo(int, double)", "foo")
  UT_FUNCTION_CHECK("unsigned int foo(int, double)", "foo")

  // Templates
  UT_FUNCTION_CHECK("unsigned int Test::Bar<T, N>::print() const"
                    " [with T = Test::Foo, unsigned int N = 3u]",
                    "Test::Bar<T, N>::print")
  UT_FUNCTION_CHECK("Test::Bar<T, N> Test::Bar<T, N>::print() const"
                    " [with T = Test::Foo, unsigned int N = 3u]",
                    "Test::Bar<T, N>::print")
  UT_FUNCTION_CHECK("void Test::Bar<T, N>::parameterized(U) const"
                    " [with unsigned int O = 4u, U = Test::Foo,"
                    " T = Test::Foo, unsigned int N = 3u]",
                    "Test::Bar<T, N>::parameterized")

  // Functions returning functions
  UT_FUNCTION_CHECK("void (* Test::Foo::func() const)()",
                    "Test::Foo::func")
  UT_FUNCTION_CHECK("void (Test::Foo::* Test::Foo::method() const)(int)volatile",
                    "Test::Foo::method")
  UT_FUNCTION_CHECK("void (Test::Foo::* Test::Foo::super())"
                    "(void (Test::Foo::*)(int)volatile)const",
                    "Test::Foo::super")
  } // Function

It works in combination with gcc's __func__ macro.

The StringRef class is similar to llvm::StringRef.

I think it should cover your needs if you can afford the extra parsing. It's quite fast: no backtracking and no dynamic allocation, so should not be an issue (especially compared to writing to a file...).

Hope it helps.

这篇关于宏获取最新的命名空间和函数名(而不是完整的签名)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆