有没有一种方法可以缩短这种情况?

Luk*_*těk 50 c++ algorithm if-statement while-loop simplify

while (temp->left->oper == '+' || 
       temp->left->oper == '-' || 
       temp->left->oper == '*' || 
       temp->left->oper == '/' || 
       temp->right->oper == '+' || 
       temp->right->oper == '-' || 
       temp->right->oper == '*' || 
       temp->right->oper == '/')
{
    // do something
}
Run Code Online (Sandbox Code Playgroud)

为了清楚起见:temp是一个指向以下node结构的指针:

struct node
{
    int num;
    char oper;
    node* left;
    node* right;
};
Run Code Online (Sandbox Code Playgroud)

pad*_*ddy 58

当然,您可以只使用一串有效的运算符并进行搜索。

#include <cstring>

// : :

const char* ops = "+-*/";
while(strchr(ops, temp->left->oper) || strchr(ops, temp->right->oper))
{
     // do something
}
Run Code Online (Sandbox Code Playgroud)

如果您担心性能,那么也许进行表查找:

#include <climits>

// : :

// Start with a table initialized to all zeroes.
char is_op[1 << CHAR_BIT] = {0};

// Build the table any way you please.  This way using a string is handy.
const char* ops = "+-*/";
for (const char* op = ops; *op; op++) is_op[*op] = 1;

// Then tests require no searching
while(is_op[temp->left->oper] || is_op[temp->right->oper])
{
     // do something
}
Run Code Online (Sandbox Code Playgroud)

  • 必须对`strchr`稍加小心,因为(这是一个鲜为人知的事实)如果`temp-&gt; left-&gt; oper`或`temp-&gt; right-&gt; oper`等于`'\,这也是正确的。 0'`。但是实际上,这可能是一个很好的解决方案。 (14认同)
  • 这里是否有理由在`std :: string`和`.find()`上使用`strchr`? (9认同)
  • 您可能希望将实现提取到单独的函数中。 (3认同)
  • @paddy我不认为他在寻找高尔夫球的答案!只是避免了`||`语句的长链。 (3认同)
  • 是的,OP 的目标是缩短循环条件。使用 `ops.find(temp-&gt;left-&gt;oper) != std::string::npos` 并不像使用 `strchr` 那么短。但是,当然,正如评论中指出的,在搜索“\0”的情况下,“strchr”的行为是不同的,因此使用它也可能被视为潜在错误或实际错误,具体取决于输入。 (2认同)

JeJ*_*eJo 35

是的,的确可以!

将有效字符存储到一个std::array或什至一个普通数组,然后将标准算法应用于该数组std::any_of以检查条件。

#include <array>     // std::array
#include <algorithm> // std::any_of

const std::array<char, 4> options{ '+', '-', '*', '/' };
const auto tester = [&temp](char c) { return temp->left->oper == c || temp->right->oper == c; };
const bool isValid = std::any_of(options.cbegin(), options.cend(), tester);

while(isValid) // now the while-loop is simplified to
{
    // do something
}
Run Code Online (Sandbox Code Playgroud)

可以通过打包到接受node要检查的对象的函数中来对其进行清理。

#include <array>     // std::array
#include <algorithm> // std::any_of

bool isValid(const node& temp)
{
    static constexpr std::array<char, 4> options{ '+', '-', '*', '/' };
    const auto tester = [&temp](char c) { return temp->left->oper == c || temp->right->oper == c; };
    return std::any_of(options.cbegin(), options.cend(), tester);
}
Run Code Online (Sandbox Code Playgroud)

可以在 while-loop

while (isValid(temp)) // pass the node to be checked
{
    // do something
}
Run Code Online (Sandbox Code Playgroud)

  • 它不是`std :: any_of`而不是`std :: all_of`吗? (3认同)

Jar*_*d42 30

创建一个子函数,

bool is_arithmetic_char(char)
{
// Your implementation or one proposed in another answers.
}
Run Code Online (Sandbox Code Playgroud)

然后:

while (is_arithmetic_char(temp->left->oper)
    || is_arithmetic_char(temp->right->oper))
{
    // do something
}
Run Code Online (Sandbox Code Playgroud)

  • @alephzero:观看谈话_可测试性和良好设计之间的深层协同作用-如果没有,那么。它可能会给您另一个角度。 (5认同)
  • 我从来不相信这种“微重构”。它所做的就是将代码中的任何错误从您可以看到它们的地方*在它们使用的上下文中*移动到您看不到的地方。当然,如果相同的测试发生在应用程序的其他地方,那么这是将其排除的一个很好的理由。 (2认同)
  • @alephzero在这种情况下我更喜欢这种子函数,因为(1)如果您想稍后添加运算符,它们会抽象出可能更改的定义(2)它们提供一个小的可测试接口(3)它们可以记录在头文件中。 (2认同)

MCC*_*CCS 14

C样式:

int cont = 1;
while(cont)
    switch(temp->left->oper) {
    case '+':
    case '-':
    ...
    case '/':
        // Do something
        break;
    default:
        cont = 0;
    }
Run Code Online (Sandbox Code Playgroud)

// Do something如果要声明变量,则可能需要用大括号括起来。

  • 这不仅仅是“ C风格”。对于这种确切情况,有充分的理由更喜欢这样做,因为编译器能够比理论上的混乱情况更有效地构造[跳转表](https://en.wikipedia.org/wiki/Branch_table) )无关的“ if”检查。即使不能做到这一点,“我正在将一堆不同的常量与同一个变量进行比较”也是提供给编译器的好信息,可以帮助编译器更好地进行优化。 (7认同)
  • 将条件更改为`while(1)`会更好。将第一个“ break”更改为“ continue”;将默认大小写更改为break;并在`switch`之后添加另一个中断。我在解释器中多次使用了这种模式。 (2认同)
  • @Alexander,不,[GCC 9.1为切换案例添加了跳转表,位测试和决策树](https://gcc.gnu.org/gcc-9/changes.html)。[TCase1](https://godbolt.org/z/nxn-Pr)[TCase2](https://godbolt.org/z/b87f6N) (2认同)

L. *_* F. 6

您可以构造一个包含选项的字符串并搜索字符:

#include <string>

// ...

for (auto ops = "+-*/"s; ops.find(temp-> left->oper) != std::string::npos ||
                         ops.find(temp->right->oper) != std::string::npos;)
    /* ... */;
Run Code Online (Sandbox Code Playgroud)

"+-*/"s是一个C ++ 14功能。std::string ops = "+-*/";在C ++ 14之前使用。


Quu*_*one 5

编程是寻找冗余并消除冗余的过程。

struct node {
    int num;
    char oper;
    node* left;
    node* right;
};

while (temp->left->oper == '+' || 
       temp->left->oper == '-' || 
       temp->left->oper == '*' || 
       temp->left->oper == '/' || 
       temp->right->oper == '+' || 
       temp->right->oper == '-' || 
       temp->right->oper == '*' || 
       temp->right->oper == '/') {
    // do something
}
Run Code Online (Sandbox Code Playgroud)

这里的“重复单元”是什么?好吧,我看到了两个实例

   (something)->oper == '+' || 
   (something)->oper == '-' || 
   (something)->oper == '*' || 
   (something)->oper == '/'
Run Code Online (Sandbox Code Playgroud)

因此,让我们将重复的部分分解为一个函数,这样我们只需要编写一次即可。

struct node {
    int num;
    char oper;
    node* left;
    node* right;

    bool oper_is_arithmetic() const {
        return this->oper == '+' || 
               this->oper == '-' || 
               this->oper == '*' || 
               this->oper == '/';
    }
};

while (temp->left->oper_is_arithmetic() ||
       temp->right->oper_is_arithmetic()) {
    // do something
}
Run Code Online (Sandbox Code Playgroud)

- 缩短!
(原始代码:17行,其中8个为循环条件。修订后的代码:18行,其中2个为循环条件。)