如何在c ++中创建一个干净的级联if结构?

Adr*_*ian 8 c++ coding-style

我正在使用boost的正则表达式库,我发现确定是否找到了命名匹配然后使用该信息有点烦人.要检测命名匹配,我想这样做:

typedef boost::match_result<string::const_iterator> matches_t;
typedef matches_t::const_reference match_t;
boost::regex re("(?:(?<type1>aaaa)|(?<type2>bbbb)" /*...*/ "|(?<typeN>abcdefg)");
string str(SOME_STRING);
matches_t what;
boost::match_flag_type flags = boost::match_default;

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  if((match_t type1 = what["type1"]).matched)
  {
     // do stuff with type1
  }
  else if((match_t type2 = what["type2"]).matched)
  {
     // do stuff with type2
  }
  // ...
  else if((match_t typeN = what["typeN"]).matched)
  {
     // do stuff with typeN
  }
}
Run Code Online (Sandbox Code Playgroud)

如果这样可行,那就太好了.范围将限制在if的主体,内存可以有效使用,看起来相当干净.遗憾的是,它无法正常工作,因为您无法在列表中定义变量.:(

这可能是一种可能性:

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  match_t found = what["type1"];
  if(found.matched)
  {
     // do stuff with type1
  }
  else if((found = what["type2"]).matched)
  {
     // do stuff with type2
  }
  // ...
  else if((found = what["typeN"]).matched)
  {
     // do stuff with typeN
  }
}
Run Code Online (Sandbox Code Playgroud)

但match_t是一个const引用,因此它不可分配. (tl; dr我也不知道底层类型是什么,一般我不想知道,因为我更喜欢一个更通用的解决方案,我可以在这个正则表达式的例子之外使用.甚至std :: move()用于什么[...]更加冗长,文档并没有说它使用了sub_match的移动语义.当然,由于第一句中给出的原因,所有这一切都没有实际意义.段.)

另一个选择是做到这一点:

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  match_t type1 = what["type1"];
  if(type1.matched)
  {
     // do stuff with type1
  }
  else {
    match_t type2 = what["type2"];
    if(type2.matched)
    {
       // do stuff with type2
    }
    // ...
          else {
            match_t typeN = what["typeN"];
            if((match_t typeN = what["typeN"]).matched)
            {
               // do stuff with typeN
            }
          }
    // ...
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我不喜欢由于大括号的深层嵌套.

也许break在每个if主体的末尾滥用循环结构,如下所示:

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  do{
    {
      match_t type1 = what["type1"];
      if(type1.matched)
      {
         // do stuff with type1
         break;
      }
    }
    {
      match_t type2 = what["type2"];
      if(type2.matched)
      {
         // do stuff with type2
         break;
      }
    }
    // ...
    {
      match_t typeN = what["typeN"];
      if(typeN.matched)
      {
         // do stuff with typeN
         break;
      }
    }
  } while(0);
}
Run Code Online (Sandbox Code Playgroud)

哪个更好,但仍然不是很好.使用宏,可以隐藏大部分噪声.喜欢:

#define IF(declare, cond) do{{declare;if(cond){                
#define ELSE_IF(declare, cond) break;}}{declare; if(cond){     
#define ELSE break;}}{{                                        
#define END_IF break;}}}while(0);                              

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  IF(match_t type1 = what["type1"], type1.matched)
  {
     // do stuff with type1
  }
  ELSE_IF(match_t type2 = what["type2"], type2.matched)
  {
     // do stuff with type2
  }
    // ...
  ELSE_IF(match_t typeN = what["typeN"], typeN.matched)
  {
     // do stuff with typeN
  }
  END_IF
}
Run Code Online (Sandbox Code Playgroud)

大括号实际上是由宏隐含的,但通过重新设置它可以使读数更清晰.

我能想到的另一个选择是进入boost :: sub_match类并添加一个转换函数来将该类型转换为bool,其返回值将是该matched成员的返回值.然后我可以在if表达式中声明一个match_t变量,它会自动转换为if的布尔值.我不确定我是否在那里并且它不是通用的.

在风格上,我建议好坏的(只有最后3个实际工作,所以我可能会限制他们的评论).

另外,有没有人有更好的建议?请说明为什么你认为他们更好.

Sig*_*erm 6

通常建议避免嵌套if- 它们使代码更难以阅读.如果有嵌套if,它应该可能被函数调用替换.

在您的情况下,您需要使用循环.

你的第二个例子:

if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
  match_t found = what["type1"];
  if(found.matched)
  {
     // do stuff with type1
  }
  else if((found = what["type2"]).matched)
  {
     // do stuff with type2
  }
  // ...
  else if((found = what["typeN"]).matched)
  {
     // do stuff with typeN
  }
}
Run Code Online (Sandbox Code Playgroud)

BEGS循环:

const char *types[] = {"type1", "type2", "typeN", 0};
for(const char **cur = types; *cur; cur++){
    found = what[*cur];
    if (found.matched){
         //initiate robot uprising
         break;
    }
}
Run Code Online (Sandbox Code Playgroud)

你所有的其他例子(IMO)都是一种糟糕的编码风格.我更喜欢保持循环和ifs短.如果它不适合20行代码,那么最好做一些非常复杂的事情(这不是你的情况).如果它没有做任何复杂的事情,它需要重组.