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