关于C++20中T*转bool被视为narrowing转换的技术疑问
C++20窄化转换特性:T*转bool的疑问解答
我的基础理解
bool x = 2; // 属于窄化转换 bool x {2}; // 编译错误,列表初始化严格禁止窄化,2转bool会丢失信息 bool x = 1; // 正常编译,1与true等价,无信息丢失 bool x {1}; // 允许,1可以安全转换为bool,不属于窄化
疑问1:T*转bool的窄化特性与应用场景
你给出的bool p = new char*;是拷贝初始化,拷贝初始化允许窄化转换(可能触发警告),而C++20的特性核心针对列表初始化场景:
- C++20之前,指针转bool并不被视为窄化转换,所以
bool p {new char*};可以正常编译; - C++20修正了这一规则,将指针转bool归类为窄化转换——指针包含完整内存地址信息,转成bool后仅保留“是否为空”的状态,大量信息丢失,符合窄化转换的定义(转换后无法还原原始值),因此列表初始化时会触发警告或错误(取决于编译器设置)。
这个特性的应用场景是避免误操作:防止开发者在初始化时意外将指针赋值给bool变量,减少因信息丢失导致的潜在逻辑错误。你给出的拷贝初始化代码能正常编译,是因为拷贝初始化本身不强制禁止窄化,仅可能发出警告;若改用列表初始化bool p {new char*};,C++20标准下的编译器会触发窄化相关的警告或错误。
疑问2:nullptr_t转bool的编译失败原因
你给出的代码bool x = nullptr编译失败的直接原因是语法错误——代码末尾缺少分号,补上分号后bool x = nullptr;可正常编译:std::nullptr_t可以隐式转换为bool,结果为false。
关于文章的表述,更准确的解释是:std::nullptr_t到bool的转换属于窄化转换,因此列表初始化bool x {nullptr};会被禁止(编译错误);但拷贝初始化bool x = nullptr;允许窄化,所以可以编译。文章中“bool is constructible from std::nullptr_t”指的是可通过直接初始化(如bool(nullptr))构造bool对象,而“not convertible”的表述并不准确,实际std::nullptr_t可隐式转换为bool,只是该转换属于窄化。
疑问3:GCC中不同初始化方式的差异
这是三种初始化方式的规则差异导致的:
- 列表初始化
{}:严格禁止窄化转换,所以int value {2.5};直接报错——double转int会丢失小数部分,属于明确的窄化。而bool res {new int};在C++20下属于窄化转换,GCC默认仅发警告而非错误,是出于历史兼容考虑,可通过编译选项-Werror=narrowing强制转为错误。 - 直接初始化
():不检查窄化转换,允许任何合法的隐式转换,所以bool res (new int);可正常编译——指针转bool的隐式转换合法,直接初始化不会因窄化阻止它。
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

