Since C++20, the new revolutionary standard has introduced a meta class named std::source_location
which provides information about the current line number, file name and function name of the executing context. This new class is included in a standalone header <source_location>
and also a better alternative to the old methods like __LINE__
and __FILE__
.
std::source_location
shows some magic mechanism to make an access to the code context without any macro expansions, as if it ‘knows’ the compile-time names and numbers where it is placed, as follows:
#include <print>
#include <source_location>
namespace {
void print_loc(const std::source_location& loc) {
std::print("File: {}, Position: ({},{}), Function: {}\n",
loc.file_name(), loc.line(), loc.column(), loc.function_name()
);
}
}
struct foo {
foo(std::source_location loc = std::source_location::current()) {
print_loc(loc);
}
void baz(int number, std::source_location loc = std::source_location::current()) const {
print_loc(loc);
}
};
int main() {
const foo obj;
obj.baz(1);
}
The output of the function name is implementation-defined, due to the different name mangling rules among GCC, Clang and MSVC. Both GCC and Clang respect the Itanium ABI, and however Microsoft maintains its unique and uniform ABI on Windows known as the MSVC ABI or Windows COM ABI.
File: /app/example.cpp, Position: (23,13), Function: int main()
File: /app/example.cpp, Position: (25,10), Function: int main()
GCC is licensed under the GNU General Public License (GPL), specifically the GPLv3 with a special exception. Microsoft open-sourced its STL implementation on GitHub, with an Apache-2.0-with-LLVM-exception license. The latest GCC codebase defines a new built-in function named __builtin_source_location
to generate information of the call site directly. In addition, MSVC’s STL continues to use existing built-in functions such as __builtin_LINE
, __builtin_COLUMN
, __builtin_FILE
, __builtin_FUNCTION
/__builtin_FUNCSIG
that has been introduced in older versions.
// [support.srcloc.cons], creation
static consteval source_location
current(__builtin_ret_type __p = __builtin_source_location()) noexcept {
source_location __ret;
__ret._M_impl = static_cast <const __impl*>(__p);
return __ret;
}
_NODISCARD static consteval source_location current(const uint_least32_t _Line_ = __builtin_LINE(),
const uint_least32_t _Column_ = __builtin_COLUMN(), const char* const _File_ = __builtin_FILE(),
#if _USE_DETAILED_FUNCTION_NAME_IN_SOURCE_LOCATION
const char* const _Function_ = __builtin_FUNCSIG()
#else // ^^^ detailed / basic vvv
const char* const _Function_ = __builtin_FUNCTION()
#endif // ^^^ basic ^^^
) noexcept {
source_location _Result{};
_Result._Line = _Line_;
_Result._Column = _Column_;
_Result._File = _File_;
_Result._Function = _Function_;
return _Result;
}
When using an early version of the compiler that does not contain <source_location>
, writing a custom source_location
class with similar functions whose values refer to the evaluation results of these built-in functions is an acceptable consideration. Literally, GCC does provide the same functions as MSVC in GCC 10 without full support of the C++20 Standard.