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.
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.
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.
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.
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.
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.)
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);
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With