C++20立即函数默认参数替换上下文及编译器行为合规性判定
C++20 std::source_location 编译器行为合规性判断
场景1:loc为consteval立即函数
测试代码
#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!"); }
运行表现
- MSVC输出符合预期,两次输出分别对应
main中调用log的位置、fun中调用log的位置 - GCC两次输出均指向
loc函数的定义行
合规性结论
MSVC行为符合C++标准,GCC实现存在缺陷
按照C++标准规则,
std::source_location::current()作为默认实参时,求值时机是所属函数的调用点,而非定义点。loc作为立即函数,其默认参数的求值也遵循该规则:每次log被调用触发loc()调用时,才会求值current(),取值为当前log的调用位置。GCC提前在loc定义阶段完成求值,不符合标准要求。
场景2:loc为普通非立即函数
修改点
将loc的定义改为:
auto loc(std::source_location x = std::source_location::current() ) { return x; }
运行表现
- GCC编译通过,输出符合预期,两次输出分别对应两次
log的调用位置 - MSVC编译报错,提示
std::source_location::current调用不属于常量表达式
合规性结论
GCC行为符合C++标准,MSVC实现存在缺陷
std::source_location::current()是consteval立即函数,但C++标准明确允许其作为普通函数的参数默认实参使用:该场景下默认实参在调用点求值,无需满足常量表达式要求,属于标准允许的合法例外场景。MSVC未适配该特殊规则,错误抛出编译错误,不符合标准要求。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

