In C++20 a new feature was added to get the source location information: https://en.cppreference.com/w/cpp/utility/source_location
Here is a slightly modified example from that page, where an addition immediate function loc
is used to get the source location:
#include <iostream>
#include <string_view>
#include <source_location>
consteval auto loc(std::source_location x = std::source_location::current() ) { return x; }
void log(const std::string_view message,
const std::source_location location = loc()) {
std::cout << "file: "
<< location.file_name() << "("
<< location.line() << ":"
<< location.column() << ") `"
<< location.function_name() << "`: "
<< message << '\n';
}
template <typename T> void fun(T x) { log(x); }
int main(int, char*[]) {
log("Hello world!");
fun("Hello C++20!");
}
In the latest MSVC 2019 it prints as in the original example from cppreference.com:
file: main.cpp(25:5) `main`: Hello world!
file: main.cpp(20:5) `fun`: Hello C++20!
But in GCC the same line is indicated twice in the output:
file: /app/example.cpp(8:51) ``: Hello world!
file: /app/example.cpp(8:51) ``: Hello C++20!
demo: https://gcc.godbolt.org/z/nqE4cr9d4
Which of the compilers is right here?
And if define loc
function not as immediate one:
auto loc(std::source_location x = std::source_location::current() ) { return x; }
then the output of GCC changes and resembles the original example:
file: /app/example.cpp(20:8) `int main(int, char**)`: Hello world!
file: /app/example.cpp(17:42) `void fun(T) [with T = const char*]`: Hello C++20!
While MSVC refuses to compile it with the error:
error C7595: 'std::source_location::current': call to immediate function is not a constant expression
demo: https://gcc.godbolt.org/z/vorW4f9ax
Please also suggest, which compiler is right in not-immediate case as well?
This is explained in 17.8.2.1.2 [support.srcloc.class]
(emphasis mine):
Remarks: Any call to
current
that appears as a default member initializer (11.4), or as a subexpression thereof, should correspond to the location of the constructor definition or aggregate initialization that uses the default member initializer. Any call tocurrent
that appears as a default argument (9.3.3.6), or as a subexpression thereof, should correspond to the location of the invocation of the function that uses the default argument (7.6.1.2).
From this, I deduce that GCC is right.
When the call to current
happens in line 5, it returns a source_location
object that "correspond[s] to the location of the invocation of the function (in this case the function loc
) that
uses the default argument".
In this case the invocation location is 8:51
(the expression const std::source_location location = loc()
).
Why the function name is empty is explained by the following:
__func__
.
Element Value function_name_
A name of the current function such as in __func__
(9.5.1) if any, an empty string otherwise.
__func__
appears as a default argument, the name is undefined. I know that examples are nonnormative text, but this clearly describes the intent:[Example:
struct S { S() : s(__func__) { } // OK const char* s; }; void f(const char* s = __func__); // error: __func__ is undeclared
— end example]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With