2012-02-03 8 views
11

¿Hay una macro C++ que obtenga el nombre de espacio de nombre y la función actual? Ejemplo:Macro para obtener el espacio de nombres actual y el nombre de la función (pero no la firma completa)?

namespace foo { 
    namespace bar { 
    void baz(int i, double d) { 
     std::cout << MACRO << std::endl; 
    } 
    } 
} 

imprimiría foo::bar::baz. Sé de __FUNCTION__ pero no da el espacio de nombre. Y BOOST_CURRENT_FUNCTION da la firma completa, incl. argumentos y retorno Tipo:

void foo::bar::baz(int, double) 

Tal vez, es posible escribir una macro que extrae el espacio de nombres y el nombre de la función de BOOST_CURRENT_FUNCTION?

Quiero que para fines de registro, para obtener una cadena de registro como

foo::bar::baz -- blah logging message blah 
+0

No creo que haya ninguna plataforma independiente para obtener la firma completa de la función. Sin embargo, ¿por qué no puedes usar el combo de '__FILE__' y' __LINE__'? Te dará casi el mismo efecto; además, es más rápido ubicar en el código de los registros en comparación con la búsqueda de una función. – iammilind

+0

@iammilind: En realidad, quiero usar el contenido de la macro como el nombre del registrador en log4cxx. Esos nombres de registradores son jerárquicos y puede establecer diferentes niveles de registro para diferentes espacios de nombres, etc. Entonces, lo que realmente hago es algo como 'log4cxx :: LoggerPtr logger (log4cxx :: Logger :: getLogger (" foo.bar.baz ")) ; LOG4CXX_INFO (logger, "blah logging message blah"); 'El MACRO debe completar la parte' foo.bar.baz'. No quería hacerlo tan complicado en mi publicación. – Frank

Respuesta

4

Por lo que yo sé, no es posible (no portable). Sin embargo, desde la firma completa puede extraer esos argumentos. Por supuesto que requiere el análisis sintáctico dicha firma ... que no es tan fácil: x

Aquí es la función que uso en la actualidad

// What we want to consume: 
// void 
// signed short 
// unsigned int 
// Test::Bar<T, N> 
// 
static char const* consumeType(char const* const begin, char const* const end){ 
    static StringRef const Signed("signed"); 
    static StringRef const Unsigned("unsigned"); 

    char const* it = begin; 

    if (startsWith(it, Signed)) { it += Signed.size() + 1; } 
    else if (startsWith(it, Unsigned)) { it += Unsigned.size() + 1; } 

    // jump over the return type 
    size_t templateNest = 0; 
    while (it != end) { 
    if (*it == ' ' and templateNest == 0) { break; } 
    if (*it == '<') { ++templateNest; } 
    if (*it == '>' and templateNest > 0) { --templateNest; } 

    ++it; 
    } 

    return it; 
} // consumeType 

// 
// \param signature: signature as returned by __func___ on gcc 
// \return: full name, included namespace qualifier and class (if any) 
// 
// void Test::Bar<T, N>::parameterized(U) const 
// [with unsigned int O = 4u, U = Test::Foo, 
// T = Test::Foo, unsigned int N = 3u] 
// -> Test::Bar<T, N>::parameterized 
// 
StringRef parseFunctionName(StringRef const signature) { 
    char const* begin = signature.begin(); 
    char const* end = signature.end(); 

    // Jump over the return type 
    begin = consumeType(begin, end); 
    if (begin == end) { return signature; } 

    // skip the space right after the return type 
    ++begin; 
    if (begin == end) { return signature; } 

    // if we encounter a '(' then it means that we return a function, 
    // and we once again need to jump over the return type 
    if (*begin == '(') { 
    begin = consumeType(++begin, end); 

    // skip the space 
    ++begin; 
    if (begin == end) { return signature; } 
    } 

    // and finally, we got the beginning, and we need to get the end, which is 
    // the first opening '(' 
    char const* e = std::find(begin, end, '('); 
    return StringRef(begin, e - begin); 
} // parseFunctionName 

Y su accompagnying pruebas:

#define UT_FUNCTION_CHECK(Signature_, Name_) \ 
    UT_CHECK(parseFunctionName(StringRef(Signature_)) == Name_); 

void Function() { 
    // Regular functions 
    UT_FUNCTION_CHECK("int main()", "main") 
    UT_FUNCTION_CHECK("int foo(int, double)", "foo") 
    UT_FUNCTION_CHECK("unsigned int foo(int, double)", "foo") 

    // Templates 
    UT_FUNCTION_CHECK("unsigned int Test::Bar<T, N>::print() const" 
        " [with T = Test::Foo, unsigned int N = 3u]", 
        "Test::Bar<T, N>::print") 
    UT_FUNCTION_CHECK("Test::Bar<T, N> Test::Bar<T, N>::print() const" 
        " [with T = Test::Foo, unsigned int N = 3u]", 
        "Test::Bar<T, N>::print") 
    UT_FUNCTION_CHECK("void Test::Bar<T, N>::parameterized(U) const" 
        " [with unsigned int O = 4u, U = Test::Foo," 
        " T = Test::Foo, unsigned int N = 3u]", 
        "Test::Bar<T, N>::parameterized") 

    // Functions returning functions 
    UT_FUNCTION_CHECK("void (* Test::Foo::func() const)()", 
        "Test::Foo::func") 
    UT_FUNCTION_CHECK("void (Test::Foo::* Test::Foo::method() const)(int)volatile", 
        "Test::Foo::method") 
    UT_FUNCTION_CHECK("void (Test::Foo::* Test::Foo::super())" 
        "(void (Test::Foo::*)(int)volatile)const", 
        "Test::Foo::super") 
    } // Function 

Funciona en combinación con la macro __func__ de gcc.

La clase StringRef es similar a llvm::StringRef.

Creo que debería cubrir sus necesidades si puede pagar el análisis adicional. Es bastante rápido: sin retrocesos ni asignación dinámica, por lo que no debería ser un problema (especialmente en comparación con escribir en un archivo ...).

Espero que ayude.

+0

¡Gracias! Trataré de hacerlo compilar. ¿Cómo se define 'consumeType'? – Frank

+1

@Frank: No entiendo muy bien la pregunta ... ¿se define como está escrito en la respuesta? –

+0

Oh, mi culpa, no importa. – Frank

Cuestiones relacionadas