24

In the following toy-example, I would like to get the name of a function. The function itself was given as an std::function argument. Is it possible in C++ to get name of a std::function object?

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

void magic(){};

//somewhere in the code
printName(magic());

output: magic

Otherwise I would have to give the function's name as a second parameter.

Null
  • 1,950
  • 9
  • 30
  • 33
hr0m
  • 2,643
  • 5
  • 28
  • 39

6 Answers6

29

No there isn't. Function names (like variable names) are compiled out so they are not visible at run-time.

Your best bet is to pass the name of the function (use a std::string or a const char*) as you've suggested yourself. (Alternatively you could base a solution on __func__ which was introduced in C++11.)

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
13

The answer is no, but you could make something like

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

And then define a preprocessor

#define NAMED_FUNCTION(var, type, x) NamedFunction<type> var(#x,x)
...
NAMED_FUNCTION(f, void(), magic);
thorsan
  • 1,034
  • 8
  • 19
7

Given a std::function it has a member function called target_type which returns the typeid of the stored function object. That means you can do

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

This returns an implementation-defined string that is unique for each type. With Visual Studio, this string is human-readable already. With gcc (or maybe it's glibc? I don't know who takes care of what in detail) you need to use abi::__cxa_demangle after including <cxxabi.h> to get a human-readable version of the type name.

EDIT
As Matthieu M. pointed out, given a function pointer, the type returned by this will just be the function's signature. For example:

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

This will output (assuming you demangled if necessary) int (*)() which is not the function's name.

This method will work with classes though:

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

printName(Function{});

This will print Function as desired, but then doesn't work for function pointers.

SirGuy
  • 10,660
  • 2
  • 36
  • 66
  • and Visual Studio is actually MSVC :p – coyotte508 Jun 01 '16 at 00:17
  • 1
    There is a big difference between the name of a function and its signature; on [gcc](http://ideone.com/Gp3oWQ) I get `PFvvE` as a display for `void magic()` because only the signature is encoded. Not sure about MSVC. – Matthieu M. Jun 01 '16 at 08:56
3

You could also have your function with a string parameter for the name and then use a macro to call it

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

See example

Urban
  • 399
  • 1
  • 5
  • 11
1

Maintain your own map from function pointer to name.

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_()

Simply do REGISTER_NAME(magic); to register the name magic to the function magic. This should be done at file scope, either in a header or a cpp file.

Now we check if the std::function has a function pointer matching its signature stored inside of it. If so, we look it up in our name_map, and return the name if we find it:

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

this is generally a bad idea.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
-4

I think the simplest solution is to use typeid(fun).name() for example like this:

#include <typeinfo>

#include <stdio.h>

void foobar( void )
{
}

int main()
{
  printf( "%s\n", typeid( foobar ).name() );
  return 0;
}

Now, it have a lot of drawbacks, and I would not recommend using that. First of all, IIRC it shows the symbol of the function, not the name you used in source code. Also, the name will change from compiler to compiler. And finally, RTTI is slow.

[edit] Also, I'm not sure how it works with std::function. Never used that, honestly.

user3459474
  • 145
  • 1
  • 7