Article by Ayman Alheraki on March 18 2026 02:33 PM
std::source_location in Modern C++: A Better Way to Build Debugging, Logging, and Diagnostics SystemsIn low-level and high-performance C++ systems, one of the most persistent challenges is obtaining accurate, maintainable, and low-overhead diagnostic information.
For decades, developers relied on macros such as:
__FILE____LINE____FUNCTION__While effective, these approaches suffer from serious limitations:
They rely on macros (not type-safe)
They pollute interfaces
They are difficult to integrate into modern abstractions
They lack composability
With C++20, the language introduces a powerful and elegant solution:
std::source_location— a zero-overhead, type-safe mechanism for capturing call-site information
std::source_location?std::source_location is a lightweight object that captures:
File name
Line number
Column number
Function name
It is defined in:
The key capability lies in:
std::source_location::current()This function retrieves information about the call site, not where it is written.
void log(const std::source_location& loc = std::source_location::current()) { std::cout << "File: " << loc.file_name() << "\n" << "Line: " << loc.line() << "\n" << "Function: " << loc.function_name() << "\n";}
int main() { log();}File: main.cppLine: 12Function: mainstd::source_location is ImportantOld approach:
Modern approach:
void log(std::string_view msg, const std::source_location& loc = std::source_location::current());No macros. Cleaner. Safer.
The most powerful feature is:
The default argument is evaluated at the call site, not at the function definition.
This enables writing reusable utilities without losing context.
No heap allocation
Typically optimized as compile-time constants
Comparable cost to macros
This makes it suitable even for:
real-time systems
embedded systems
high-frequency logging
void log_info(std::string_view message, const std::source_location& loc = std::source_location::current()) { std::cout << "[INFO] " << loc.file_name() << ":" << loc.line() << " (" << loc.function_name() << ") " << message << "\n";}Usage:
log_info("Server started");
[[noreturn]]void fail(std::string_view msg, const std::source_location& loc = std::source_location::current()) { throw std::runtime_error( std::string(msg) + " at " + loc.file_name() + ":" + std::to_string(loc.line()));}
void assert_true(bool condition, const std::source_location& loc = std::source_location::current()) { if (!condition) { std::cerr << "Assertion failed at " << loc.file_name() << ":" << loc.line() << "\n"; std::abort(); }}In systems like:
Boost.Asio servers
trading engines
distributed systems
You can attach source_location to:
log entries
tracing events
metrics systems
without affecting performance.
Sometimes you want to propagate location manually:
void wrapper(const std::source_location& loc = std::source_location::current()) { log_info("Wrapped call", loc);}source_locationYou can embed it into structures:
struct ErrorContext { std::string message; std::source_location location;};std::expected
std::expected<int, ErrorContext> parse() { return std::unexpected(ErrorContext{ "parse error", std::source_location::current() });}This creates rich error propagation without exceptions.
const std::source_location& loc = std::source_location::current()This ensures:
correct call-site capture
zero additional effort for callers
Only pass explicitly when forwarding context.
Even though it is lightweight:
avoid excessive logging in hot paths
use conditional logging
Use with:
constexpr flags
compile-time log levels
to eliminate overhead entirely in release builds.
You can migrate:
From:
To:
inline void log_error(std::string_view msg, const std::source_location& loc = std::source_location::current());Rust: uses file!(), line!() macros
C++: now provides a type-safe alternative without macros
This aligns C++ with modern language design principles while preserving performance.
std::source_location is not just a small utility feature.
It represents a design shift in Modern C++:
Moving from macro-based debugging to type-safe, composable diagnostics.
For advanced developers building:
compilers
backends
system tools
performance-critical applications
this feature becomes a foundational building block.
The difference between basic logging and professional-grade diagnostics systems often lies in details like this.
And std::source_location is one of those details that quietly transforms your entire architecture.