C++20中decltype(h{}.t())是否合法?对应标准规则是什么?
关于
decltype(h{}.t())在C++20中的合法性问题 decltype(h{}.t())是合法的C++20表达式,MSVC的报错属于编译器实现偏差,不符合C++标准规则。
代码与编译器行为对比
原始代码如下:
struct d; struct h { static auto t() -> d; }; using a = decltype(h::t()); // 所有编译器均正常 using b = decltype(decltype(h{})::t()); // 所有编译器均正常 using c = decltype(h{}.t()); // Clang、GCC正常,MSVC报错
MSVC抛出的错误信息:
(6): error C2027: use of undefined type 'd' (1): note: see declaration of 'd'
C++20标准的具体规则依据
核心规则来自两个标准章节:
- [expr.ref] 成员访问表达式:静态成员的访问不依赖于对象表达式的求值。也就是说,
h{}这个临时对象的构造操作不会被实际执行,编译器只需要确认h是完整类型即可(这里h已经完成定义)。 - [decltype] 类型推导:
decltype(e)中的表达式e属于不求值操作数(unevaluated operand)。对于静态成员函数调用,即使返回类型d不完整,也不影响表达式的合法性——因为在不求值语境下,只需要函数的声明,不需要函数定义或返回类型的完整定义。
另外,原始代码中的h是聚合类型(无用户声明的构造函数),h{}是聚合初始化,但同样在不求值语境下,初始化操作不会被实际执行,因此不需要考虑聚合初始化的具体细节。
编译器偏差的规避方案
MSVC错误地在不求值语境中要求返回类型d完整,我们可以通过以下方式规避:
- 给
h添加用户定义的默认构造函数(即使是= default),此时h不再是聚合类型,MSVC会正确识别到对象表达式在不求值语境下无需执行构造,从而停止报错:
struct d; struct h { static auto t() -> d; h() = default; }; using c = decltype(h{}.t()); // 所有编译器均正常
需要注意的是,使用std::declval<h>().t()仍会触发MSVC的错误,这同样是编译器的实现问题——std::declval本身就是专为不求值语境设计的工具,不应该要求返回类型d完整。
内容的提问来源于stack exchange,提问作者303
相关产品推荐
相关产品推荐

