2

I want to write a function that can obtain caller's function name, or at least its length, at compile time. I think obtaining std::source_location::current() is close to what I want and currently I'm able to do this:

consteval auto funcNameLength(const std::source_location &Loc = std::source_location::current()) {
  const char *Name = Loc.function_name();
  std::size_t Length = 0;
  while (Name[Length] != '\0')
    ++Length;
  return Length;
}

int main() {
  constexpr auto L = funcNameLength(); // L == 4
}

or this (with a constexpr strlen):

consteval auto
funcNameLength(std::size_t Length = constexpr_strlen(
                   std::source_location::current().function_name())) {
  return Length;
}

int main() { constexpr auto L = funcNameLength(); }

However, that is not enough for me. I need to use the length as a constant expression to do something before returning to caller, e.g.

consteval auto
doSomething(std::size_t Length = constexpr_strlen(
                   std::source_location::current().function_name())) {
  int A[Length]; // Error: Length is not a constant expression.
}

int main() {
  doSomething();
}

Is this achievable?

3
  • function arguments can't be part of constexpr even if function is constexpr. Why you need A and why it need to be C-array? What are you trying to accomplish? Explaining your solution to this goal doesn't look like a good approach. Commented Aug 5 at 15:37
  • I am really curious about your use case. Shipping code with extra debug information is usually a sign that some other part of the development process is missing. E.g. unit tests, with enough unit tests and say exceptions/error handling in your code you shouldn't need it. My experience is that code with unit testing hardly requires any logging/debugging helpers in code just normal error handling/reporting. And logging based on explicit customer requirements (e.g. for traceability, who did what when). So yes I am with @MarekR here Commented Aug 5 at 17:02
  • @PepijnKramer Actually I'm working on a Clang-based tool. I've written a simple wrapper for Clang's diagnostic engine and it would be nice if I can print the name of the checker that initiates the current diagnostic. Of course this can be done from source_location::current, but Clang seems to suggest against runtime strings in its related interfaces (see issue #116169) and I feel their attitude somewhat unclear on this. That's why I keep trying to generate and manipulate compile-time strings. Commented Aug 5 at 18:01

1 Answer 1

6

Function parameters are not constant expression, even in consteval function.

You have to pass argument as template.

Since C++20, you might have structural types as template parameter, so

constexpr std::size_t constexpr_strlen(const char* s)
{
    std::size_t i = 0;
    while (s[i]) ++i;
    return i;
}

template <std::size_t N = 42> // Some hard coded limit for non literal string
struct LiteralString
{
    consteval LiteralString(const char *s) { std::copy(s, s + constexpr_strlen(s), &data[0]); }
    consteval LiteralString(const char (&s)[N]) { std::copy(s, s + N, &data[0]); }

    static constexpr std::size_t size = N;
    std::array<char, N> data{};
};

Then you might do something like:

template <LiteralString S = std::source_location::current().function_name()>
void foo() {
    constexpr std::size_t len = constexpr_strlen(S.data.data());
    // ...
}

int main() {
    foo();   // empty string for clang/msvc :(
    foo<>(); // empty string for clang/msvc :(
}

Unfortunately, only gcc feeds current source_location in template parameter Demo.

MACRO might be a workaround Demo

#define FOO() foo<std::source_location::current().function_name()>()

int main() {
    foo();   // empty string for clang/msvc :(
    foo<>(); // empty string for clang/msvc :(

    // "int main()" or "int __cdecl main(void)"
    foo<std::source_location::current().function_name()>();
    FOO();
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.