You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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标准的具体规则依据

核心规则来自两个标准章节:

  1. [expr.ref] 成员访问表达式:静态成员的访问不依赖于对象表达式的求值。也就是说,h{}这个临时对象的构造操作不会被实际执行,编译器只需要确认h是完整类型即可(这里h已经完成定义)。
  2. [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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:42:38