Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the name of a std::function

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.

like image 852
hr0m Avatar asked May 31 '16 12:05

hr0m


People also ask

How do you call a STD function in C++?

The stored callable object is called the target of std::function . If a std::function contains no target, it is called empty. Invoking the target of an empty std::function results in std::bad_function_call exception being thrown.

What is C++ std :: function?

C++ Library - <functional> Instances of std::function can store, copy, and invoke any Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.

Does std :: function allocate?

As it happens, std::function is guaranteed to not allocate if constructed from a function pointer, which is also one word in size. So constructing a std::function from this kind of lambda, which only needs to capture a pointer to an object and should also be one word, should in practice never allocate.

Is STD function a pointer?

No. One is a function pointer; the other is an object that serves as a wrapper around a function pointer. They pretty much represent the same thing, but std::function is far more powerful, allowing you to do make bindings and whatnot.


5 Answers

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

like image 134
Bathsheba Avatar answered Sep 24 '22 05:09

Bathsheba


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);
like image 45
thorsan Avatar answered Sep 22 '22 05:09

thorsan


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.

like image 39
SirGuy Avatar answered Sep 23 '22 05:09

SirGuy


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

like image 3
Urban Avatar answered Sep 24 '22 05:09

Urban


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.

like image 1
Yakk - Adam Nevraumont Avatar answered Sep 20 '22 05:09

Yakk - Adam Nevraumont