Skip to content
Why is a raven like a writing desk?

Thoughts both confusing and enlightening.

Why is a raven like a writing desk?

Thoughts both confusing and enlightening.

std::source_location is Broken

elbeno, 16 November, 202316 November, 2023

Everyone knows that the best way to get something done on the Internet is with an inflammatory title and a potentially incorrect contention, so here goes.

What do you if you want to capture/log the filename of an assertion? Prior to C++20, you use good old __FILE__, which gives you a C-style array of chars. But of course this is a macro, and means that your logging/assertion code has to be a macro. With all the usual downsides of macros. Ho hum, that’s how it is for now, and it works. You go on your way.

After upgrading to C++20, you wonder if you can upgrade your logging/assertion code to use std::source_location. Then maybe you could get rid of the macros. It looks odd at first, because you have to set it up as a default argument to your log function. But hey, this was someone’s clever solution to the problem, right? Obviously arguments are supplied at the call site, and default arguments are arguments, so they are too. So the std::source_location default argument picks up the location of the call site, and you can grab the file_name from it as a const char*.

But… now it doesn’t work. Because that’s not how your logging works. You’re working in embedded. No room for strings in your binary. Instead, you model your (statically-known) strings as types like string_constant<'H', 'e', 'l', 'l', 'o'>, you use nm to extract the symbols from your library, and you generate tiny function specializations which turn the types into numbers, and melt away with LTO. (Like this.)

You need strings to be types. You need to know the size at compile time. std::source_location::file_name() gives you a const char* – you don’t know the size of the string. And because it has to be a function argument, it can’t be constexpr. There is no way to get back into type land. (At least, none that I know of yet, and believe me, I’ve tried. If you know how, let me know!) It’s the same story for the intrinsics that std::source_location is built upon (__builtin_FILE_NAME).

So you sadly accept that until and unless you get jam tomorrow another mechanism to do this, be it constexpr function arguments or whatever, you’re stuck with __FILE__, which works, because it gives you a sized char array which you can turn into a type.

Of course the irony here is that std::source_location provides information that is known only at compile time. But we can’t use that information fully at compile time, because it’s inadequately specified/implemented.

C++

Post navigation

Previous post
Next post

Related Posts

C++ Tuples: the missing functionality

6 April, 201530 June, 2015

C++ provides a strange mix of compile-time and runtime functionality for dealing with tuples. There are some interesting parts, like std::tie to destructure a tuple, and std::tuple_cat to join together several tuples into one. So there is evidence that the standard has been influenced by some functional programming ideas, but…

Read More

Formatted Diagnostics with C++20

10 December, 202410 December, 2024

C++26 adds formatted diagnostics with static_assert, something like this: The benefit of course is that when such an assertion fails, the compiler outputs a diagnostic that we control. But can this be done in C++20? Well, this is C++! So the answer is a qualified yes – we can get…

Read More

How to print anything in C++ (part 2)

1 February, 201530 June, 2015

Part 1 Part 2 Part 3 Part 4 Part 5 Postscript We have a basic plan, and the ability to detect concrete types. But how can we detect whether an object supports output with operator<<? For this, there is a recently-discovered amazing trick. Here’s the code: template using void_t =…

Read More
©2026 Why is a raven like a writing desk? | WordPress Theme by SuperbThemes