Reputation: 55
I'm working with __ PRETTY_FUNCTION __, C++11, that is formated like: (type Class::Object(parameters), but I need to format my string like (Class::Object()).
I know how to remove "type" from my string with constexpr. I can simply return a pointer skipping space, like this:
inline constexpr const char* removeType(const char* expression) noexcept
{
return (*expression == ' ') ? expression+1 : removeType(expression+1);
}
This is working very well! But I can't think of a way to remove "parameters" from my string. I thought I could find "(" in my original expression and put a ") \ 0" after that. But I can't change this string because it's a constant, and that would also change the __ PRETTY_FUNCTION __ return behavior. So, what can I do to create a new string (char* or const char*) in a constexpr and format it removing something in the middle of it?
Upvotes: 0
Views: 394
Reputation: 4079
I took a crack, ignoring the obvious caveat that __PRETTY_FUNCTION__
is a propriety GNU convention that can't be counted on for any guarantees in the formatting. My strategy was to start at the last ')', and then do a search for '(' while balancing parenthesis to avoid tricky parameters like function pointers. But then I was able to make this:
struct baz {
template <typename T>
decltype(auto) complex(int y, foo<int(*)()> a) const noexcept {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return 42;
}
};
baz{}.complex<decltype(&biff)>(42, foo<decltype(&bar)>{});
Which produced:
decltype(auto) baz::complex(int, foo<int (*)()>) const [with T = float (*)()]
So, I made a helper function to do a search, balancing []
, <>
, {}
, and ()
, just in case.
constexpr const char* balancedReverseSeek(bool(*predicate)(char), const char* begin, const char* current) {
size_t squareLevel = 0;
size_t carrotLevel = 0;
size_t parenLevel = 0;
size_t braceLevel = 0;
const char* c = current;
for (; c != begin && (!predicate(*c) || squareLevel || carrotLevel || parenLevel || braceLevel); --c) {
switch (*c) {
case ')':
parenLevel++;
break;
case '(':
parenLevel--;
break;
case ']':
squareLevel++;
break;
case '[':
squareLevel--;
break;
case '>':
carrotLevel++;
break;
case '<':
carrotLevel--;
break;
case '}':
braceLevel++;
break;
case '{':
braceLevel--;
break;
}
}
return c;
}
Then this seems to work ok, and it gets the class name (baz::complex
):
constexpr std::string_view getName(std::string_view prettyName) {
if (prettyName.empty()) {
return prettyName;
}
const char* signatureEnd = prettyName.data() + (prettyName.size() - 1);
const char* paramEnd = balancedReverseSeek([](char c) { return c == ')'; }, prettyName.data(), signatureEnd);
if (paramEnd != prettyName.data()) {
paramEnd--;
}
const char* nameEnd = balancedReverseSeek([](char c) { return c == '('; }, prettyName.data(), paramEnd);
if (nameEnd != prettyName.data()) {
nameEnd--;
}
const char* nameBegin = balancedReverseSeek([](char c) { return c == ' '; }, prettyName.data(), nameEnd);
return { nameBegin, nameEnd - nameBegin + 1 };
}
Demo: https://godbolt.org/z/W578vP
Upvotes: 1