Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What advantages does C++20's std::source_location have over the pre-defined macros __FILE__, __LINE__ and __FUNCTION__?

Tags:

c++

c++20

In my current project, I have used:

Log(__LINE__, __FUNCTION__, message);

But the new C++20 utility class std::source_location comes with functions line(), column(), file_name(), function_name(), which do the same thing. So, the new C++20 way would be:

log(std::string message,const std::source_location& location = std::source_location::current())
{
    std::cout << "Debug:"
              << location.file_name() << ':'
              << location.line() << ' '
              << message << '\n';
}

What is the advantage of the new, C++20 way over the old standard double-underscore macros, __LINE__, __FILE__, __func__, which have already been standard C++ for a long time?

I'm trying to decide if the advantage(s) are so great as to justify modifying the code in my current projects to use the new std::source_location object in preference to the macros.

like image 628
Roshan M Avatar asked Jun 14 '21 12:06

Roshan M


People also ask

What does __ file __ mean in C?

__FILE__ This macro expands to the name of the current input file, in the form of a C string constant. This is the path by which the preprocessor opened the file, not the short name specified in ' #include ' or as the input file name argument. For example, "/usr/local/include/myheader.

What is __ LINE __ in C?

__LINE__ is a preprocessor macro that expands to current line number in the source file, as an integer. __LINE__ is useful when generating log statements, error messages intended for programmers, when throwing exceptions, or when writing debugging code.

What is __ Cplusplus macro?

C++ preprocessor macro __cplusplus The __cplusplus preprocessor macro is defined if the compilation unit is compiled with a C++ compiler. Its value corresponds to the C++ standard that the compiler uses to compile a compilation unit.


3 Answers

Your example is the best motivation I can think of. In the past __LINE__ and _FILE__ were the best excuse to use macros for debug logs. Now this does not hold anymore.

In the past you had basically two choiches. Either let the caller pass info on where the logging happens:

log(__LINE__,__FILE__,"Hello World");

or use a macro to get same output via

log("Hello World");
//^--- log must be a macro if we want this __LINE__ in the log

Both is very inconvenient, because either the user has to pass parameters that have to be the same anyhow on each call, or we need to use a macro with all the known downsides. With source_location we can get log("Hello World"); without any macros involved, but still include line and file of the call, because default parameters are substituted at the call site. For example:

#include <source_location>
#include <string>
#include <iostream>

void log(std::string message,const std::source_location& location = std::source_location::current())
{
    std::cout << "Debug:"
              << location.file_name() << ':'
              << location.line() << ' '
              << message << '\n';
}


int main() {
    log("hello");
    log("world");
}

Output:

Debug:/app/example.cpp:15 hello
Debug:/app/example.cpp:16 world
like image 157
463035818_is_not_a_number Avatar answered Oct 19 '22 14:10

463035818_is_not_a_number


Pre-C++20 you had to choose between being verbose (passing __LINE__, __FILE__, __func__ to each call manually) and using a macro to do that for you.

std::source_location gives you a nice calling syntax without a macro. There are no other hidden advantages.

Note that both Clang, GCC, and MSVC have the same non-standard extension that lets you do it pre-C++20: __builtin_LINE(), __builtin_FILE(), and __builtin_FUNCTION() that can be used as default arguments to achieve the same effect. You should be able to write your own class source_location using them as well.

like image 38
HolyBlackCat Avatar answered Oct 19 '22 14:10

HolyBlackCat


The main advantage of std::source_location is mostly convenience, because it represents a source location with a single, easily storable structure.

It has also the advantage of not being based on preprocessor magic, so for the language it is not just an integer literal but a valid type, which is much nicer from the point of view of type-safety.

If you are fine with the older approach, there's no reason to change good, already working code. This is generally true for most new features though, not only for std::source_location.

like image 2
mcilloni Avatar answered Oct 19 '22 14:10

mcilloni