6.4 Selection statements 4

书籍:《ISO/IEC 14882 2014》

说明:以上内容大部分来自腾讯元宝。

如何理解以下内容:

4 The value of a condition that is an initialized declaration in a statement other than a switch statement is the value of the declared variable contextually converted to bool (Clause 4).  If that conversion is ill-formed, the program is ill-formed.  The value of a condition that is an initialized declaration in a switch statement is the value of the declared variable if it has integral or enumeration type, or of that variable implicitly converted to integral or enumeration type otherwise.  The value of a condition that is an expression is the value of the expression, contextually converted to bool for statements other than switch;  if that conversion is ill-formed, the program is ill-formed.  The value of the condition will be referred to as simply “the condition” where the usage is unambiguous.

在除switch语句之外的语句中初始化声明的条件的值是声明变量的值在上下文中转换为bool(第4条)。如果转换是病态的,那么程序就是病态的。在switch语句中作为初始化声明的条件的值,如果它是整型或枚举类型,则为声明的变量的值,否则为隐式转换为整型或枚举类型的变量的值。作为表达式的条件的值是表达式的值,在上下文中将其转换为bool,用于除switch以外的语句;如果转换是病态的,那么程序就是病态的。在用法明确的情况下,条件的值将被简单地称为“条件”。

在 C++ 中,条件语句(如 ifwhileswitch)中声明并初始化的变量,其值如何被判定?以下是针对标准的详细解释,结合示例说明其行为:


​1. 核心规则​

​(1) 非 switch 语句中的条件​
  • ​条件类型​​:初始化声明(如 if (int x = f()))。
  • ​值的判定​​:
    变量的值被 ​​隐式转换为 bool 类型​(通过上下文转换,见 [conv.contextual])。
  • ​非法转换​​:
    如果变量类型无法隐式转换为 bool,程序会报错(ill-formed)。
​(2) switch 语句中的条件​
  • ​条件类型​​:初始化声明(如 switch (int x = f()))。
  • ​值的判定​​:
    变量的值必须为 ​整型或枚举类型​,或可隐式转换为整型/枚举类型。
  • ​非法类型​​:
    若变量无法转换为整型/枚举类型,程序会报错。
​(3) 普通表达式作为条件​
  • ​值的判定​​:
    表达式的值被隐式转换为 bool 类型(如 if (a > b))。
  • ​非法转换​​:
    如果表达式无法转换为 bool,程序会报错。

​2. 示例解析​

​(1) 非 switch 语句中的条件​
if (int x = 42) {          // x 的值为 42 → 转换为 bool → true
    // 条件成立
}

if (bool flag = true) {    // 直接使用 bool 类型 → 合法
    // 条件成立
}

struct S {};
if (S s = S{}) {           // S 无法隐式转换为 bool → 编译错误!
    // ...
}
​(2) switch 语句中的条件​
switch (int x = 42) {      // x 是整型 → 合法
    case 42: 
        break;
}

enum E { A, B };
switch (E e = A) {         // e 是枚举类型 → 合法
    case A: 
        break;
}

switch (double d = 3.14) {// 错误:double 无法隐式转换为整型/枚举
    // ...
}
​(3) 普通表达式作为条件​
int a = 0;
if (a) {                   // a 转换为 bool → false
    // 条件不成立
}

if (a != 0) {              // 表达式直接转换为 bool → false
    // 条件不成立
}

​3. 关键细节​

​(1) 隐式转换的触发​
  • ​类类型的 bool 转换​​:
    如果类定义了 operator bool(),则允许隐式转换:
    struct Wrapper {
        explicit operator bool() const { return true; }
    };
    if (Wrapper w = Wrapper{}) { // 合法:调用 operator bool()
        // ...
    }
  • ​禁止 explicit 转换​​:
    若转换运算符标记为 explicit,则无法在条件中隐式触发:
    struct ExplicitWrapper {
        explicit operator bool() const { return true; }
    };
    if (ExplicitWrapper w = ExplicitWrapper{}) { // 错误:explicit 转换需要显式调用!
        // ...
    }
​(2) switch 中的类型限制​
  • ​允许的类型​​:
    boolcharshortintlongenum 等。
  • ​禁止的类型​​:
    浮点类型(如 floatdouble)、类类型(除非定义了到整型的转换)。

​4. 为什么会有不同规则?​

​(1) if/while 需要布尔条件​
  • 这些语句需要明确的真假判断,因此要求条件最终转换为 bool
  • ​示例​​:if (x) 中的 x 必须能明确表示“真”或“假”。
​(2) switch 需要整型或枚举类型​
  • switch 的 case 标签要求整型常量表达式,因此条件的值必须是整型或可隐式转换的类型。
  • ​示例​​:case 1: 需要一个整型值,无法接受类类型。

​5. 常见错误场景​

​(1) 类型不匹配​
if (std::string s = "hello") { // 错误:std::string 无法转换为 bool
    // ...
}
​(2) switch 中使用浮点类型​
switch (double x = 3.14) {     // 错误:double 无法转换为整型
    case 3.14: // 语法错误:case 标签必须是整型常量
        break;
}

​6. 总结​

​场景​​条件类型​​值判定规则​​合法示例​​非法示例​
if/while初始化声明变量隐式转换为 boolif (int x = 42)if (S s = S{})(无转换)
switch初始化声明变量为整型或可隐式转换为整型switch (int x = 42)switch (double d = 3.14)
普通表达式表达式(非声明)表达式隐式转换为 boolif (a > b)if (std::string())

​7. 实际应用建议​

  1. ​优先使用显式类型​​:
    在条件中尽量使用 bool 或整型变量,避免隐式转换的潜在风险。

    bool is_valid = check_validity();
    if (is_valid) { ... } // 更清晰
  2. ​利用作用域限制变量​​:
    在条件中声明变量,限制其作用域(如 if (auto ptr = get_ptr()))。

    if (auto ptr = std::make_unique<int>(42)) {
        // 使用 ptr
    } // ptr 自动销毁
  3. ​避免 switch 中的非常规类型​​:
    确保 switch 条件的类型是整型或枚举类型。


通过理解这些规则,可以避免因条件类型错误导致的编译问题,并编写更健壮的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值