在下面的玩具示例中,我想获得一个函数的名称。函数本身作为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
否则我必须将函数的名称作为第二个参数。
答案 0 :(得分:28)
不,没有。函数名称(如变量名称)将被编译出来,因此它们在运行时不可见。
您最好的选择是传递函数的名称(使用std::string
或const 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一起使用。从来没用过,老实说。