获取 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::string
或 const 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);
在下面的玩具示例中,我想获取一个函数的名称。函数本身作为 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::string
或 const 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);