获取 std::function 的名称

Get the name of a 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

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

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

最好的办法是按照您自己的建议传递函数名称(使用 std::stringconst char*)。 (或者,您可以基于 C++11 中引入的 __func__ 解决方案。)

我认为最简单的解决方案是使用 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 一起使用。老实说,没用过。

答案是否定的,但你可以做类似

的东西
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);

维护您自己的从函数指针到名称的映射。

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 中查找它,如果找到它,return 名称:

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

这通常不是一个好主意。

给定一个 std::function 它有一个名为 target_type 的成员函数,其中 returns 存储函数对象的 typeid。这意味着您可以

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

这 returns 一个实现定义的字符串,对于每种类型都是唯一的。使用 Visual Studio,这个字符串已经是人类可读的了。使用 gcc(或者可能是 glibc?我不知道谁会详细处理什么)你需要在包含 <cxxabi.h> 之后使用 abi::__cxa_demangle 来获得类型名称的人类可读版本。

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

int function(){return 0;}
printName(function);

这将输出(假设您在必要时进行了分解)int (*)(),这不是函数的名称。

此方法适用于 类 不过:

struct Function
{
    int operator()(){return 0;}
};

printName(Function{});

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

您也可以让函数的名称带有字符串参数,然后使用宏来调用它

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