2011-10-08 9 views
19

En C++, cuando usamos typeid para obtener el nombre de tipo de un objeto o clase, se mostrará una cadena decorada (mutilada). Yo uso cxxabi a demangle que:Eliminando espacio de nombre de tipo en C++

#include <cxxabi.h> 
#include <typeinfo> 

namespace MyNamespace { 

class MyBaseClass 
{ 
public: 
    const std::string name() 
    { 
     int status; 
     char *realname = abi::__cxa_demangle(typeid (*this).name(),0,0, &status); 
     std::string n = realname; 
     free(realname); 
     return n; 
    } 
}; 

} 

int main() 
{ 
    MyNamespace::MyBaseClass h; 
    std::cout << h.name() << std::endl; 
} 

La salida de gcc es:

MyNamespace :: MyBaseClass

Necesito quitar MyNamespace:: de cadena anterior. puedo eliminarlos mediante la manipulación de cadena .

Pero hay una manera estándar con cxxabi u otras bibliotecas para hacer esto o una solución clara? (Por lo menos portátil entre gcc y Visual C++)

+2

+1, pregunta informativa. – iammilind

+0

IIRC sería legal que una implementación compatible simplemente devuelva la misma cadena (por ejemplo, "godzilla") para cualquier clase. – 6502

+0

Puede utilizar diferentes convenciones de nomenclatura para clases y espacios de nombres, para que pueda ver inmediatamente cuál es el que está en 'X :: Y :: Z :: MyType'. –

Respuesta

8

No hay una forma estándar de hacer esto, punto, porque no hay una forma estándar de hacer cambios de nombre. Cómo representar los nombres fue intencionalmente no especificado. No hay ABI en el estándar de C++. La función que está usando, abi::__cxa_demangle, es parte de Itanium C++ ABI. Esa función puede o no existir en otra parte.

En lo que respecta a una forma de hacer lo que desea con el Itanium C++ ABI, intencionalmente no proporcionan esa capacidad.

3

No sé si esto correspondería a sus necesidades, pero me ha gustado mencionarlo.

Hay algo que puede hacer para obtener el nombre de la clase que escribió. Y puede considerarse como portable entre gcc y Visual C++.

En GCC hay una variable magia llamado __ FUNCIÓN __ como parte de la gnu c language extensions, que tratada como una variable , en C++. (El tratamiento difiere en C de acuerdo con la versión de GCC).

En Visual Studio hay una macro predefinida que tiene el mismo nombre y hace el mismo trabajo. La descripción es here.

Se utilizan __ __ FUNCIÓN para obtener el nombre de la función actual. Por lo tanto, para obtener el nombre de la clase, puede ser que usted puede utilizarlo en constructor de la clase así:

namespace MyNamespace 
{ 
    class MyBaseClass 
    { 
    public: 
     MyBaseClass(): myName(__FUNCTION__){} 
     string name() { return myName; } 
    private: 
     string myName; 
    }; 
} 

Así, se obtiene "MyBaseClass" respuesta si se llama a name() función de una instancia de esta clase.

+0

pero, este enfoque tiene un problema, no puede usarse en clases derivadas que 'name()' devuelve el nombre de clase derivado. (y cada clase derivada debe anular su constructor nuevamente) – deepmax

+0

@MasoudM. No es una característica standad C++, en lugar de específica para gcc y VS. Pero incluso en versiones antiguas se proporciona. Puede consultar los enlaces sobre eso. Y sí, tienes razón sobre el problema derivado de la clase. No puedo entender ahora cómo superar eso. Pero debería haber una manera :) – etipici

+0

'__func__' se agregó a C++ 11 para proporcionar oficialmente esta funcionalidad, aunque en forma de una variable oculta en lugar de una macro. MSVC aún no lo admite, aunque fingir es bastante fácil. –

1

Si solo quiere definir una función de miembro que devolverá el nombre-cadena de la clase, sin el espacio de nombres, entonces me pregunto por qué incluso usaría cxxabi o incluso __FUNCTION__ o cualquier otra cosa, aparte de simplemente haciendo esto:

namespace MyNamespace 
{ 
    class MyBaseClass 
    { 
    public: 
     //make the function const as well 
     std::string name() const { return "MyBaseClass"; } 
    }; 
} 

que significa que usted tiene el control total sobre la aplicación de la clase, entonces ¿por qué hacer que complican cuando sólo uno return es suficiente? Se puede añadir otra función miembro, así:

std::string fullname() const { return "MyNamespace::MyBaseClass"; } 

Tenga una mirada en este tema de alguna manera relacionado, tal vez obtendrá más pistas:

+0

Thnx para la respuesta, pero fue discutido antes y encontré una buena práctica para mi proyecto que necesita un patrón extraño: [http://stackoverflow.com/questions/7691697/](http://stackoverflow.com/questions/ 7691697 /) – deepmax

+0

@MasoudM .: Acabo de agregar un enlace. Eche un vistazo a eso también. – Nawaz

1

investigué cxxabi y otra bibliotecas de C++ para este problema y no hay ningún método predefinido para eliminar los espacios de nombres de eso (al menos en mi Google).

Me pregunto por qué no quieres manipular la cuerda ?!

la mejor solución y totalmente portátil (probado en gcc y VC++) es simipily a continuación:

return n;

return n.substr(n.find_last_of(':')+1);

cuando se busca n de dos puntos de la última (= lastColorPos) y capturar una cadena de lastColorPos hasta el final, es definidamente el nombre de la clase.

+3

Esto también elimina los nombres de clase así como los nombres de espacio de nombres. Considera 'struct Foo {struct Bar {...}; ...}; '. –

+2

Para aclarar el punto de David, piense en lo que esta respuesta podría hacer a una clase con un nombre demandado 'SomeType '. – arman

0
std::string removeNS(const std::string & source, const std::string & namespace_) 
{ 
    std::string dst = source; 
    size_t position = source.find(namespace_); 
    while (position != std::string::npos) 
    { 
     dst.erase(position, namespace_.length()); 
     position = dst.find(namespace_, position + 1); 
    } 
    return dst; 
} 

int main() 
{ 
    MyNamespace::MyBaseClass h; 
    std::cout << removeNS(h.name(), "MyNamespace::") << std::endl; 
} 
Cuestiones relacionadas