Подтвердить что ты не робот

Получить имя функции 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

В противном случае мне нужно было бы присвоить имя функции второму параметру.

4b9b3361

Ответ 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. Никогда не использовал это, честно говоря.