Video Link: C++ Weekly - Ep 21 C++17’s if and switch Init Statements

应用场景

首先看下其等效表达[1]

1
2
3
4
5
6
7
{
  init_statement
  if constexpr(optional) ( condition )
    statement-true
  else
    statement-false
}

与普通的if几乎相同,唯一的区别是最外层的{}提供了一块私有域。即init_statement中定义的变量不会再对if外的域产生影响,并及时回收,即精准作用域。这曾经是需要通过显示{}、或lambda表达式、或抽取函数等方式才能达到相同效果。

场景1:变量初始化行为仅对当前条件作用域有效,其生命期随条件块结束即可终结。

曾几何时,当如下格式的代码:

1
2
3
4
5
if () {
} else if () {
} else {
}
afterCondition()

else if处需要一个初始化,才能进行继续进行判断,可能会写成:

1
2
3
4
5
6
7
8
9
if () {
afterCondition()
}

init_if_condition;
if () {
} else {
}
afterCondition()

亦或是:

1
2
3
4
5
6
init_if_condition_only_else_if_needed;
if () {
} else if () {
} else {
}
afterCondition()

使用该特性即可简单的改为:

1
2
3
4
5
if () {
} else if (init_if_condition; ) {
} else {
}
afterCondition()

更为直接的获得连贯简洁的表达,不用多次调用条件块后的任务,亦不用提供一个更大作用域的变量。

场景2:if else if的连贯性被else if条件所需的变量定义所以破坏。

除了上述两个场景,其他便是一个写书写上的改善,也能带来一定的效果,举例如下:

https://gitee.com/harmonyos/OpenArkCompiler/blob/master/src/maple_me/src/me_alias_class.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// This phase performs alias analysis based on Steensgaard's algorithm and
// represent the resulting alias relationships in the Maple IR representation
bool MeAliasClass::HasWriteToStaticFinal() const {
  for (auto bIt = func.valid_begin(); bIt != func.valid_end(); ++bIt) {
    for (const auto &stmt : (*bIt)->GetStmtNodes()) {
      if (stmt.GetOpCode() == OP_dassign) {
        const auto &dassignNode = static_cast<const DassignNode&>(stmt);
        if (dassignNode.GetStIdx().IsGlobal()) {
          const MIRSymbol *sym = mirModule.CurFunction()->GetLocalOrGlobalSymbol(dassignNode.GetStIdx());
          if (sym->IsFinal()) {
            return true;
          }
        }
      }
    }
  }
  return false;
}

如上代码的缩进层次比较高,使用两个if来判断“全局Dassign”,使用initializer if进行改造:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// This phase performs alias analysis based on Steensgaard's algorithm and
// represent the resulting alias relationships in the Maple IR representation
bool MeAliasClass::HasWriteToStaticFinal() const {
  for (auto bIt = func.valid_begin(); bIt != func.valid_end(); ++bIt) {
    for (const auto &stmt : (*bIt)->GetStmtNodes()) {
      if (auto *dassignNode = safe_cast<const DassignNode>(stmt);
          dassignNode != nullptr && dassignNode->GetStIdx().IsGlobal()) {
        const MIRSymbol *sym = mirModule.CurFunction()->GetLocalOrGlobalSymbol(dassignNode.GetStIdx());
        if (sym->IsFinal()) {
          return true;
        }
      }
    }
  }
  return false;
}

将针对dassignNode的判断集中在一个if表达式中,同时也较少了一级缩进层次。

注:如果不进行显示dassignNode != nullptr判空处理,亦可以写成if (auto *dassignNode = safe_cast<const DassignNode>(stmt) && dassignNode->GetStIdx().IsGlobal()) {,但方舟编码规范强制要求指针判空需要显示与nullptr进行比较,禁隐式转换。

参考资料

[1] if statement. https://en.cppreference.com/w/cpp/language/if