Visual Studio 2019中C2397错误与C4838警告的不一致性问询
为什么Visual Studio 2019中两种窄化转换的诊断级别不一样?
先看两个具体场景:
场景1:触发错误C2397的代码
错误提示:
conversion from 'T' to 'size_t' requires a narrowing conversion.
对应的代码:
struct Narrow { template <typename T> Narrow(T t) : szt{ t } { } std::size_t szt[1]; }; Narrow narrow{ 3 };
场景2:仅触发等级1警告C4838的代码
警告提示:
(level 1) C4838: "conversion from 'T' to 'size_t' requires a narrowing conversion".
对应的代码:
struct Narrow { template <typename T> Narrow(T t) { std::size_t arr[] { t }; } }; Narrow narrow{ 3 };
两者行为不同的原因
核心在于C++标准对不同初始化场景下的窄化转换,要求的严格程度不一样:
成员初始化列表中的数组列表初始化
第一个场景里,szt{ t }是在构造函数的成员初始化列表中对类成员数组做列表初始化。根据C++标准,这种情况下的窄化转换属于非法代码(ill-formed),编译器必须直接拒绝编译,所以VS抛出错误C2397——这是标准强制要求的行为。函数体内的局部数组列表初始化
第二个场景中,std::size_t arr[] { t }是在函数里创建局部数组并做列表初始化。标准只要求编译器对这种窄化转换给出诊断信息,但并没有强制要求必须当成错误处理。Visual Studio在这里选择以等级1警告C4838的形式提示,完全符合标准的规定,属于编译器的合理实现选择。
简言之,标准对类成员初始化的列表初始化窄化转换要求更严(必须报错),而局部变量的列表初始化窄化转换只要求给出诊断(警告即可),这就是两者行为不一致的根源。
内容的提问来源于stack exchange,提问作者mentalmushroom
相关产品推荐
相关产品推荐

