The idea is from https://stackoverflow.com/a/15775519/1277762
I added a '\0' at end of string_view so we can use data() for printf, spdlog, et al.
I use this macro to print function name with class name.
However, I find that the compiler is not smart enough to inline the string, but requires a memory copy to stack first:
https://godbolt.org/z/bqob37G3z
See the difference between CALL and CALLFUNC in main function.
Is it possible to tell compiler just put the string in some RO section, like const char *?
template<std::size_t N>
consteval const std::array<char, N> __get_function_name(const char * arr)
{
std::array<char, N> data {};
std::string_view prettyFunction(arr);
size_t bracket = prettyFunction.rfind("(");
size_t space = prettyFunction.rfind(" ", bracket) 1;
size_t i;
for (i = 0; i < bracket - space; i = 1) {
data[i] = arr[space i];
}
data[i] = '\0';
return data;
}
#define __METHOD_NAME__ __get_function_name<strlen(__PRETTY_FUNCTION__)>(__PRETTY_FUNCTION__).data()
CodePudding user response:
The compiler doesn't realize or take into account the specific behavior of puts
, namely that it doesn't store the pointer it is passed and doesn't call its caller again.
The problem is that without this knowledge the compiler has to take into account the possibility that puts
will store the pointer it is passed in e.g. a global variable, then calls its caller again, and then compares the new pointer argument with the old one stored in the global variable. These must compare unequal because they are pointers into different temporary objects, both in their lifetime. So the compiler can't reuse the same read-only static memory location as the argument to the puts
call.
So you need to tell the compiler explicitly to use a static memory location:
#define METHOD_NAME get_function_name<my_strlen(__PRETTY_FUNCTION__)>(__PRETTY_FUNCTION__)
#define CALL() { static constexpr auto v = METHOD_NAME; puts(v.data()); }
Technically the constexpr
on v
is redundant with consteval
on the function. Just constexpr
on both would also be sufficient.
If you don't add constexpr
on v
you might want to add const
though to make sure that the compiler won't need to consider the possibility that puts
will modify the contents of the string, although it seems that GCC in your example is aware of that. (That puts
takes a const char*
as argument is not sufficient to establish this.)
You can't use strlen
there by the way (assuming you want this to be portable to some other compiler beyond GCC that is supporting __PRETTY_FUNCTION__
in the way you are using it, e.g. Clang with libc ). That GCC is allowing it without diagnostic is not standard-conforming and it is not guaranteed to work on other compilers. std::strlen
is not marked constexpr
per standard. You need to write your own implementation of it and mark it constexpr
.