if 语句

来自cppreference.com
< cpp‎ | language

条件地执行另一条语句。

用于需要基于运行时或编译时条件执行的代码。

目录

[编辑] 语法

attr(可选) if ( condition ) statement-true (1)
attr(可选) if ( condition ) statement-true else statement-false (2)
(C++17 前)
attr(可选) if constexpr(可选) ( init-statement(可选) condition ) statement-true (1)
attr(可选) if constexpr(可选) ( init-statement(可选) condition ) statement-true else statement-false (2)
(C++17 起)
attr(C++11) - 任意数量的属性
condition - 下列之一
init-statement(C++17) - 下列之一
  • 一条表达式语句(可以是空语句; ”)
  • 一条简单声明,典型的是带初始化器的变量声明,但它可以声明任意多变量,或是一条分解声明
注意任何 init-statement 必须以分号 ; 结束,这是它常被非正式描述成后随分号的表达式或声明的原因。
statement-true - 任何语句(常是复合语句),若 condition 求值为 true 则执行
statement-false - 任何语句(常是复合语句),若 condition 求值为 false 则执行

[编辑] 解释

condition 在转换到 bool 后产生 true ,则执行 statement-true

若 if 语句的 else 部分存在,且 condition 在转换到 bool 后产生 false,则执行 statement-false

在第二形式的 if 语句(包含 else 者)中,若 statement-true 亦是 if 语句,则内层 if 语句必须也含有 else 部分(换言之,在嵌套 if 语句中, else 关联到最近的尚未有 else 的 if)

#include <iostream>
 
int main() {
    // 带 else 子句的简单 if 语句
    int i = 2;
    if (i > 2) {
        std::cout << i << " is greater than 2\n";
    } else {
        std::cout << i << " is not greater than 2\n";
    }
 
    // 嵌套 if 语句
    int j = 1;
    if (i > 1)
        if (j > 2)
            std::cout << i << " > 1 and " << j << " > 2\n";
        else // this else is part of if (j > 2), not of if (i > 1)
            std::cout << i << " > 1 and " << j << " <= 2\n";
 
   // 声明可用作带 dynamic_cast 的条件
   struct Base {
        virtual ~Base() {}
   };
   struct Derived : Base {
       void df() { std::cout << "df()\n"; }
   };
   Base* bp1 = new Base;
   Base* bp2 = new Derived;
 
   if (Derived* p = dynamic_cast<Derived*>(bp1)) // 转型失败,返回 NULL
       p->df();  // 不执行
 
   if (auto p = dynamic_cast<Derived*>(bp2)) // 转型成功
       p->df();  // 执行
}

输出:

2 is not greater than 2
2 > 1 and 1 <= 2
df()


若使用 init-statement ,则 if 语句等价于

{
init_statement
if constexpr(可选) ( condition )
statement-true

}

{
init_statement
if constexpr(可选) ( condition )
statement-true
else
statement-false

}

除了 init-statement 所声明的名称(若 init-statement 是声明)和 condition 所声明的名称(若 condition 是声明)在同一作用域中,也就是两个 statement 的作用域。

std::map<int, std::string> m;
std::mutex mx;
extern bool shared_flag; // 为 mx 保证
int demo() {
   if (auto it = m.find(10); it != m.end()) { return it->size(); }
   if (char buf[10]; std::fgets(buf, 10, stdin)) { m[0] += buf; }
   if (std::lock_guard lock(mx); shared_flag) { unsafe_ping(); shared_flag = false; }
   if (int s; int count = ReadBytesWithSignal(&s)) { publish(count); raise(s); }
   if (auto keywords = {"if", "for", "while"};
       std::any_of(keywords.begin(), keywords.end(),
                   [&s](const char* kw) { return s == kw; })) {
     std::cerr << "Token must not be a keyword\n");
   }
}
(C++17 起)

constexpr if

if constexpr 开始的语句被称为 constexpr if 语句

在 constexpr if 语句中, condition 的值必须能语境地转换到 bool 类型的常量表达式。若其值为 true ,则舍去 statement-false (若存在),否则舍去 statement-true

在被舍去语句中的 return 语句不参与函数返回类型推导:

template <typename T>
auto get_value(T t) {
    if constexpr (std::is_pointer_v<T>)
        return *t; // 对 T = int* 推导返回类型为 int
    else
        return t;  // 对 T = int 推导返回类型为 int
}

被舍去语句可以 odr 使用不定义的变量

extern int x; // 不要求 x 的定义
int f() {
if constexpr (true)
    return 0;
else if (x)
    return x;
else
    return -x;
}

若 constexpr if 语句出现于模板实体内,且若 condition 在实例化后不是值依赖的,则在外围模板被实例化时,被舍去语句不会被实例化。

template<typename T, typename ... Rest>
void g(T&& p, Rest&& ...rs) {
    // ... 处理 p
    if constexpr (sizeof...(rs) > 0)
        g(rs...); // 决不会对空参数列表实例化。
}

注意:在实例化后保留值依赖的例子是嵌套模板,例如

template<class T> void g() {
    auto lm = [](auto p) {
        if constexpr (sizeof(T) == 1 && sizeof p == 1) {
           // 此条件在 g<T> 实例化后保持值依赖
        }
    };
}

注意:被舍去语句不能对每种特化都为病态:

template <typename T>
void f() {
     if constexpr (std::is_arithmetic_v<T>)
         // ...
     else
       static_assert(false, "Must be arithmetic"); // 病态:对于所有 T 都非法
}

常用的变通方法是这种全部捕获语句为一条始终为 false 的类型依赖表达式:

template<class T> struct dependent_false : std::false_type {};
template <typename T>
void f() {
     if constexpr (std::is_arithmetic_v<T>)
         // ...
     else
       static_assert(dependent_false<T>::value, "Must be arithmetic"); // ok
}

出现于 constexpr if 子语句的标号(goto 目标case 标号,及 default: ) 只能在同一子语句中被引用(由 switchgoto )。

(C++17 起)

[编辑] 注意

statement_truestatement_false 不是复合语句,则处理成如同它是一样:

if (x)
    int i;
// i 不再在作用域中

与下面相同

if (x) {
    int i;
} // i 不再在作用域中

condition 若是声明,则其所引入的名称的作用域是两个语句体:

if (int x = f()) {
    int x; // 错误: x 的重声明
} else {
    int x; // 错误: x 的重声明
}

若通过 gotolongjmp 进入 statement-true ,则不执行 statement_false

(C++14 起)

不允许 switch 和 goto 跳入 constexpr if 语句的分支。

(C++17 起)

[编辑] 关键词

if, else, constexpr

[编辑] 参阅

if 语句C 文档