c++ - length - Obtener el nombre de una función std::
size of vector c++ (6)
En el siguiente ejemplo de juguete, me gustaría obtener el nombre de una función. La función en sí fue dada como un argumento std::function
. ¿Es posible en C ++ obtener el nombre de un objeto 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
De lo contrario, tendría que dar el nombre de la función como un segundo parámetro.
Creo que la solución más sencilla es usar typeid(fun).name()
por ejemplo, como este:
#include <typeinfo>
#include <stdio.h>
void foobar( void )
{
}
int main()
{
printf( "%s/n", typeid( foobar ).name() );
return 0;
}
Ahora, tiene muchos inconvenientes, y no recomendaría usar eso. En primer lugar, IIRC muestra el símbolo de la función, no el nombre que usaste en el código fuente. Además, el nombre cambiará de compilador a compilador. Y finalmente, la RTTI es lenta.
[editar] Además, no estoy seguro de cómo funciona con std :: function. Nunca usé eso, honestamente.
Dada una std::function
tiene una función miembro llamada target_type
que devuelve el typeid
de tipo del objeto de función almacenado. Eso significa que puedes hacer
void printName(std::function<void()> func){
//Need a function name()
std::cout << func.target_type().name();
}
Esto devuelve una cadena definida por la implementación que es única para cada tipo. Con Visual Studio, esta cadena ya es legible por humanos. Con gcc (o tal vez es glibc? No sé quién se ocupa de lo que se detalla) necesita usar abi::__cxa_demangle
después de incluir <cxxabi.h>
para obtener una versión legible por humanos del nombre del tipo.
EDITAR
Como señaló Matthieu M., dado un indicador de función, el tipo devuelto por esto solo será la firma de la función. Por ejemplo:
int function(){return 0;}
printName(function);
Esto dará como resultado (suponiendo que se haya desmangrado si es necesario) int (*)()
que no es el nombre de la función.
Este método funcionará con clases aunque:
struct Function
{
int operator()(){return 0;}
};
printName(Function{});
Esto imprimirá la Function
como se desee, pero luego no funciona para los punteros de función.
La respuesta es no, pero podrías hacer algo como
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)...);
}
};
Y luego definir un preprocesador
#define NAMED_FUNCTION(var, type, x) NamedFunction<type> var(#x,x)
...
NAMED_FUNCTION(f, void(), magic);
Mantenga su propio mapa desde el puntero a la función hasta el nombre.
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_()
Simplemente haz REGISTER_NAME(magic);
Para registrar el nombre de magic
a la función de magic
. Esto debe hacerse en el ámbito del archivo, ya sea en un encabezado o un archivo cpp.
Ahora verificamos si la std::function
tiene un puntero a función que coincida con su firma almacenada en su interior. Si es así, lo buscamos en nuestro name_map
nombre y devolvemos el nombre si lo encontramos:
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;
}
Esto es generalmente una mala idea.
No, no hay. Los nombres de funciones (como los nombres de variables) se compilan para que no sean visibles en tiempo de ejecución.
Lo mejor que puedes hacer es pasar el nombre de la función (usa std::string
o const char*
) como te has sugerido. (Alternativamente, podría basar una solución en __func__
que se introdujo en C ++ 11).
También podría tener su función con un parámetro de cadena para el nombre y luego usar una macro para llamarlo
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);
Ver example