Получить имя функции std::
В следующем примере игрушек я хотел бы получить имя функции. Сама функция была задана как аргумент std::function
. Возможно ли в С++ получить имя объекта 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
В противном случае мне нужно было бы присвоить имя функции второму параметру.
Ответы
Ответ 1
Нет, нет. Имена функций (например, имена переменных) компилируются, поэтому они не отображаются во время выполнения.
Лучше всего передать имя функции (используйте std::string
или const char*
), как вы сами предложили. (В качестве альтернативы вы можете найти решение на __func__
, которое было введено на С++ 11.)
Ответ 2
Ответ - нет, но вы можете сделать что-то вроде
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);
Ответ 3
Учитывая 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);
Это будет выводиться (при условии, что вы, если необходимо, demangled) int (*)()
, который не является именем функции.
Этот метод будет работать с классами:
struct Function
{
int operator()(){return 0;}
};
printName(Function{});
Это приведет к печати Function
по желанию, но затем не будет работать для указателей функций.
Ответ 4
Вы также можете использовать свою функцию со строковым параметром для имени, а затем использовать макрос для его вызова
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);
См. пример
Ответ 5
Сохраняйте свою собственную карту от указателя функции до имени.
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;
}
Это, как правило, плохая идея.
Ответ 6
Я думаю, что самым простым решением является использование 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. Никогда не использовал это, честно говоря.