获取std :: function的名称

时间:2016-05-31 12:06:34

标签: c++ c++11 std-function

在下面的玩具示例中,我想获得一个函数的名称。函数本身作为std::function参数给出。在C ++中是否可以获得std::function对象的名称?

void printName(std::function<void()> func){
    //Need a function name()
    std::cout << func.name();
}

void magic(){};

//somewhere in the code
printName(magic());

output: magic

否则我必须将函数的名称作为第二个参数。

6 个答案:

答案 0 :(得分:28)

不,没有。函数名称(如变量名称)将被编译出来,因此它们在运行时不可见。

您最好的选择是传递函数的名称(使用std::stringconst char*),因为您已经建议过了。 (或者你可以基于C ++ 11中引入的__func__的解决方案。)

答案 1 :(得分:13)

答案是否定的,但你可以做出像

这样的事情
template<class R, class... Args>
class NamedFunction
{
public:
    std::string name;
    std::function<R(Args...)> func;
    NamedFunction(std::string pname, std::function<R(Args...)> pfunc) : name(pname), func(pfunc)
    {}
    R operator()(Args&&... a)
    {
       return func(std::forward<Args>(a)...);
    }
};

然后定义预处理器

#define NAMED_FUNCTION(var, type, x) NamedFunction<type> var(#x,x)
...
NAMED_FUNCTION(f, void(), magic);

答案 2 :(得分:7)

给定std::function它有一个名为target_type的成员函数,它返回存储的函数对象的typeid。这意味着你可以做到

void printName(std::function<void()> func){
    //Need a function name()
    std::cout << func.target_type().name();
}

这将返回一个实现定义的字符串,该字符串对于每种类型都是唯一的。使用Visual Studio,此字符串已经是人类可读的。使用gcc(或者它的glibc?我不知道谁会详细说明),你需要在abi::__cxa_demangle包括<cxxabi.h>之后使用int function(){return 0;} printName(function); 来获得人类可读的版本类型名称。

修改
正如Matthieu M.指出的那样,给定一个函数指针,由此返回的类型将只是函数的签名。例如:

int (*)()

这将输出(假设您在必要时进行了解码)struct Function { int operator()(){return 0;} }; printName(Function{}); ,这不是函数的名称。

此方法适用于类:

Function

这将根据需要打印@Parsed,但不适用于函数指针。

答案 3 :(得分:2)

你也可以让你的函数使用一个字符串参数作为名称,然后使用宏来调用它

void _printName(std::function<void()> func, const std::string& funcName){
    std::cout << funcName;
}
#define printName(f) _printName(f, #f)

void magic(){};

//somewhere in the code
printName(magic);

请参阅example

答案 4 :(得分:1)

将您自己的地图从函数指针保存到名称。

template<class Sig>
std::map<Sig*, const char*>& name_map() {
  static std::map<Sig*, const char*> r;
  return r;
}

struct register_name_t {
  template<class Sig>
  register_name_t( Sig* sig, const char* name ) {
    name_map()[sig]=name;
  }
};
#define TO_STRING(A) #A
#define REGISTER_NAME(FUNC) \
   register_name_t FUNC ## _register_helper_() { \
     static register_name_t _{ FUNC, TO_STRING(FUNC) }; \
     return _; \
   } \
   static auto FUNC ## _registered_ = FUNC ## _register_helper_()

只需REGISTER_NAME(magic);magic名称注册到函数magic即可。这应该在文件范围内完成,可以在头文件或cpp文件中完成。

现在我们检查std::function是否有一个函数指针匹配其中存储的签名。如果是这样,我们会在name_map中查找,如果找到则返回名称:

template<class Sig>
std::string get_function_name( std::function<Sig> const& f ) {
  auto* ptr = f.target<Sig*>();
  if (!ptr) return {};
  auto it = name_map().find(ptr);
  if (it == name_map().end()) return {};
  return it->second;
}

这通常是一个坏主意。

答案 5 :(得分:-4)

我认为最简单的解决方案是使用typeid(fun).name(),例如:

#include <typeinfo>

#include <stdio.h>

void foobar( void )
{
}

int main()
{
  printf( "%s\n", typeid( foobar ).name() );
  return 0;
}

现在,它有很多缺点,我不建议使用它。 首先,IIRC显示函数的符号,而不是您在源代码中使用的名称。 此外,名称将从编译器更改为编译器。 最后,RTTI很慢。

[编辑] 另外,我不确定它如何与std :: function一起使用。从来没用过,老实说。