在 C++20 中,立即函数的默认参数在哪个上下文中被替换(在源位置示例中)?

Fed*_*dor 5 c++ language-lawyer c++20 consteval

在 C++20 中添加了一个新功能来获取源位置信息:https : //en.cppreference.com/w/cpp/utility/source_location

这是该页面的一个稍微修改的示例,其中使用附加立即函数loc来获取源位置:

#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!");
}
Run Code Online (Sandbox Code Playgroud)

在最新的 MSVC 2019 中,它按照来自 cppreference.com 的原始示例进行打印:

file: main.cpp(25:5) `main`: Hello world!
file: main.cpp(20:5) `fun`: Hello C++20!
Run Code Online (Sandbox Code Playgroud)

但是在 GCC 中,同一行在输出中显示了两次:

file: /app/example.cpp(8:51) ``: Hello world!
file: /app/example.cpp(8:51) ``: Hello C++20!
Run Code Online (Sandbox Code Playgroud)

演示:https : //gcc.godbolt.org/z/nqE4cr9d4

哪个编译器就在这里?

如果定义loc函数不是直接函数:

auto loc(std::source_location x = std::source_location::current() ) { return x; }
Run Code Online (Sandbox Code Playgroud)

然后 GCC 的输出改变并类似于原始示例:

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!
Run Code Online (Sandbox Code Playgroud)

虽然 MSVC 拒绝编译它并出现错误:

error C7595: 'std::source_location::current': call to immediate function is not a constant expression
Run Code Online (Sandbox Code Playgroud)

演示:https : //gcc.godbolt.org/z/vorW4f9ax

还请建议,哪个编译器在非直接情况下也是正确的?

jan*_*b04 3

17.8.2.1.2[support.srcloc.class]对此进行了解释(强调我的):

\n
\n

备注current:对显示为默认成员初始值设定项 (11.4) 或其子表达式的任何调用,都应对应于使用默认成员初始值设定项的构造函数定义或聚合初始化的位置。对它的任何调用current显示为默认参数 (9.3.3.6),\或作为其子表达式,都应对应于使用默认参数 (7.6.1.2) 的函数的调用位置

\n
\n

由此看来,GCC是对的。

\n

当调用current发生在第 5 行时,它返回一个source_location对象,该对象“对应于 使用默认参数的函数(在本例中为 function loc的调用位置” 。

\n

在这种情况下,调用位置是8:51(表达式const std::source_location location = loc())。

\n

为什么函数名称为空,解释如下:

\n
    \n
  1. 17.8.2.1.1.1(表38)告诉我们函数名称应该是“such as in” __func__
  2. \n
\n
\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n
元素价值
function_name_当前函数的名称,例如__func__(9.5.1) 中的函数(如果有),否则为空字符串。
\n
\n
    \n
  1. 9.5.1.8 示例显示,如果__func__作为默认参数出现,则名称未定义。我知道示例是非规范文本,但这清楚地描述了意图:
  2. \n
\n
\n

[例子:

\n
struct S {\nS() : s(__func__) { } // OK\nconst char* s;\n};\nvoid f(const char* s = __func__); // error: __func__ is undeclared\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\x94结束示例]

\n
\n