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

C++20中编译器可否忽略依赖类型所需的typename关键字?

MSVC与GCC/Clang在typename依赖类型处理上的差异及规范分析

有一段代码在MSVC下可正常编译,但因为依赖类型前缺失typename关键字,在GCC和Clang中会编译失败:

struct Foo { struct value{ }; };
struct Bar { int value; };

template<typename T>
constexpr size_t SIZE = sizeof(T::value); // 针对Foo的场景,这里缺失typename

constexpr size_t s1 = SIZE<Foo>; // 上面的依赖类型前未加typename
constexpr size_t s2 = SIZE<Bar>;

MSVC不要求在sizeof中写typename的逻辑看似合理——毕竟sizeof既可以作用于类型,也可以作用于变量;但GCC和Clang严格遵循C规范,哪怕是C20标准下,当上下文无法明确区分T::value是类型还是变量时,必须显式添加typename。

核心疑问

MSVC这种宽松的处理方式,到底是符合C++20规范的行为,还是属于编译器缺陷?


再看一组涉及concept的代码,三款编译器的行为差异更明显:

template<typename T>
concept A1 = sizeof(typename T::value) > 0;

template<typename T>
concept A2 = sizeof(T::value) > 0;

struct Foo { struct value{ }; };

constexpr bool v1 = A1<Foo>; // 所有编译器均返回true
constexpr bool v2 = A2<Foo>; // MSVC返回true,GCC和Clang返回false

GCC和Clang会将A2中省略typename的写法判定为非法,因此concept的判断结果为false;而MSVC则认可这种省略写法,判断结果为true。

规范依据分析

根据C++20规范的[temp.res.general]章节,并未将sizeof列入可以省略typename的场景,理论上必须显式添加typename来标记依赖类型,但规范也没有明确说明省略typename属于非法行为。


跨编译器兼容方案

要让代码在MSVC、GCC、Clang上都能正常编译运行,最稳妥的做法是始终显式添加typename标记依赖类型:

  • 第一个例子中,将sizeof(T::value)改为sizeof(typename T::value)
  • 第二个例子中,将A2的定义修改为和A1一致的写法

内容的提问来源于stack exchange,提问作者Amir Kirsh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 17:15:32