如何改进逻辑以检查4个布尔值是否与某些情况匹配

And*_*kle 117 c++ if-statement

我有四个bool值:

bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
Run Code Online (Sandbox Code Playgroud)

可接受的值是:

         Scenario 1 | Scenario 2 | Scenario 3
bValue1: true       | true       | true
bValue2: true       | true       | false
bValue3: true       | true       | false
bValue4: true       | false      | false
Run Code Online (Sandbox Code Playgroud)

因此,例如,这种情况是不可接受的:

bValue1: false
bValue2: true
bValue3: true
bValue4: true
Run Code Online (Sandbox Code Playgroud)

目前我已经提出这个if声明来检测不良情况:

if(((bValue4 && (!bValue3 || !bValue2 || !bValue1)) ||
   ((bValue3 && (!bValue2 || !bValue1)) ||
   (bValue2 && !bValue1) ||
   (!bValue1 && !bValue2 && !bValue3 && !bValue4))
{
    // There is some error
}
Run Code Online (Sandbox Code Playgroud)

可以改进/简化该陈述逻辑吗?

Gia*_*olo 196

我的目标是可读性:你只有3个场景,用3个独立的ifs处理它们:

bool valid = false;
if (bValue1 && bValue2 && bValue3 && bValue4)
    valid = true; //scenario 1
else if (bValue1 && bValue2 && bValue3 && !bValue4)
    valid = true; //scenario 2
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
    valid = true; //scenario 3
Run Code Online (Sandbox Code Playgroud)

易于阅读和调试,恕我直言.此外,您可以whichScenario在继续执行时分配变量if.

只有3个场景,我不会选择这样的"如果前三个值是真的我可以避免检查第四个值":它将使你的代码更难以阅读和维护.

不是优雅的解决方案 也许 当然,但在这种情况下还可以:简单易读.

如果您的逻辑变得更复杂,请丢弃该代码并考虑使用更多内容来存储不同的可用场景(正如Zladeck建议的那样).

我非常喜欢这个答案中给出的第一个建议:易于阅读,不易出错,易于维护

(几乎)偏离主题:

我在StackOverflow上没有写很多答案.真的很有趣的是,上面接受的答案是我历史上最受欢迎的答案(在我认为之前从未有超过5-10个赞成票),而实际上并不是我通常认为的"正确"方式.

但简单往往是"正确的方式",很多人似乎都认为这一点,我应该比我做的更多:)

  • 这可以通过将所有条件堆叠到"valid"的初始化程序中并用`||`分隔它们而不是在单独的语句块中改变`valid`来进一步简化.我不能在注释中添加一个例子,但你可以在左边垂直对齐`||`运算符,使其非常清晰; 各个条件已经根据需要加上括号(对于`if`),因此除了已经存在的表达式之外,您不需要在表达式中添加任何字符. (4认同)
  • 我把它包装在`if($ bValue1)中,因为它总是必须是真的,技术上允许一些小的性能改进(尽管我们在这里讨论可忽略的数量). (3认同)
  • FWIW:只有两种情况:前两种情况相同,不依赖于`bValue4` (2认同)

And*_*ers 122

我的目标是简单和可读性.

bool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
bool scenario2 = bValue1 && bValue2 && bValue3 && !bValue4;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;

if (scenario1 || scenario2 || scenario3) {
    // Do whatever.
}
Run Code Online (Sandbox Code Playgroud)

确保使用描述性的内容替换方案的名称以及标志的名称.如果它对您的具体问题有意义,您可以考虑这个替代方案:

bool scenario1or2 = bValue1 && bValue2 && bValue3;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;

if (scenario1or2 || scenario3) {
    // Do whatever.
}
Run Code Online (Sandbox Code Playgroud)

这里重要的不是谓词逻辑.它描述了您的域名并清楚地表达了您的意图.这里的关键是给所有输入和中间变量好名字.如果找不到好的变量名,可能表示您以错误的方式描述问题.

  • +1这也是我本来会做的.就像@RedFilter指出的那样,与接受的答案相反,这是自我记录的.在单独的步骤中为场景提供自己的名称更具可读性. (2认同)

P.W*_*P.W 104

我们可以使用卡诺图来将您的场景缩小为逻辑等式.我使用了Online Karnaugh地图求解器和4个变量的电路.

在此输入图像描述

这会产生:

在此输入图像描述

A, B, C, DbValue1, bValue2, bValue3, bValue4,这只不过是:

bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4
Run Code Online (Sandbox Code Playgroud)

所以你的if陈述变成:

if(!(bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4))
{
    // There is some error
}
Run Code Online (Sandbox Code Playgroud)
  • 当您有许多变量和许多应该评估的条件时,卡诺图特别有用true.
  • 在将true场景减少到逻辑等式之后,添加指示true场景的相关注释是一种良好的做法.

  • 虽然技术上是正确的,但此代码需要大量注释才能在几个月后由其他开发人员进行编辑. (96认同)
  • @PW这个评论似乎和代码一样可以理解,因此有点无意义.更好的评论可以解释你是如何实际提出这个等式的,即该陈述应该触发TTTT,TTTF和TFFF.那时你也可以在代码中写下这三个条件而不需要解释. (27认同)
  • @ZdeslavVojkovic:我只想在等式中加上评论.`//!(ABC + AB'C'D')(按K-Map逻辑)`.对于开发人员来说,如果他还不了解K-Maps,那将是个好时机. (21认同)
  • 我同意这一点,但IMO的问题在于它没有清楚地映射到问题域,即每个条件如何映射到特定场景,这使得难以改变/扩展.当有'E`和'F`条件和4个新场景时会发生什么?正确更新这个`if`语句需要多长时间?代码检查如何检查它是否正常?问题不在于技术方面,而在于"业务"方面. (11认同)
  • 我认为你可以分解出'A`:'ABC + AB'C'D'= A(BC + B'C'D')`(这甚至可以解释为'A(B ^ C)'(C + D')`虽然我要小心称这种'简化'). (7认同)
  • 我经常使用卡诺图来简化具有许多布尔输入的条件.当我这样做时,我通常会发现,减少的公式,措辞恰当,是对我要检查的内容的最简洁和清晰的描述.也就是说,卡诺地图往往会找到你想要的模式. (5认同)
  • @PW或者更好,`//由卡诺图简化; 必须匹配TTTT,TTTF和TFFF`,它给出了_full_名称以便于谷歌搜索,显示了预期的逻辑,并且没有跳过计算中的任何步骤(因为它没有显示任何步骤). (4认同)
  • 当我们谈论逻辑门时,我了解了数字工程中的卡诺图,其中门最小化实际上很重要.除非这是一个罕见的情况,代码需要尽可能优化,我认为交易可读性与"速度"没有关系.只是我2¢. (4认同)
  • 我会添加一些冗余的括号.许多开发人员并没有将逻辑运算符(&& vs ||)的优先级内部化为与算术运算符相同的程度,因此括号会阻止读者自己进行二次猜测. (2认同)

Zde*_*vic 58

这里真正的问题是:当其他开发人员(甚至作者)必须在几个月后更改此代码时会发生什么.

我建议将其建模为位标志:

const int SCENARIO_1 = 0x0F; // 0b1111 if using c++14
const int SCENARIO_2 = 0x0E; // 0b1110
const int SCENARIO_3 = 0x08; // 0b1000

bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = false;
bool bValue4 = false;

// boolean -> int conversion is covered by standard and produces 0/1
int scenario = bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
bool match = scenario == SCENARIO_1 || scenario == SCENARIO_2 || scenario == SCENARIO_3;
std::cout << (match ? "ok" : "error");
Run Code Online (Sandbox Code Playgroud)

如果有更多场景或更多标志,则表方法比使用标志更具可读性和可扩展性.支持新方案只需要表中的另一行.

int scenarios[3][4] = {
    {true, true, true, true},
    {true, true, true, false},
    {true, false, false, false},
};

int main()
{
  bool bValue1 = true;
  bool bValue2 = false;
  bool bValue3 = true;
  bool bValue4 = true;
  bool match = false;

  // depending on compiler, prefer std::size()/_countof instead of magic value of 4
  for (int i = 0; i < 4 && !match; ++i) {
    auto current = scenarios[i];
    match = bValue1 == current[0] && 
            bValue2 == current[1] && 
            bValue3 == current[2] && 
            bValue4 == current[3];
  }

  std::cout << (match ? "ok" : "error");
}
Run Code Online (Sandbox Code Playgroud)

  • IMO,表是最好的方法,因为它可以通过其他方案和标记更好地扩展. (6认同)
  • 不是最可维护的,但肯定简化了if条件.因此,在这里留下一些关于按位操作的注释将是绝对必要的. (4认同)
  • 如果您正在使用C++ 14或更高版本,我建议使用二进制文字作为第一个解决方案 - 0b1111,0b1110和0b1000更清晰.你可以使用标准库(`std :: find`?)来简化这一点. (4认同)
  • 我发现这里的二进制文字将是**minimal*要求,以使第一个代码干净.在目前的形式,它是完全神秘的.描述性标识符可能有所帮助,但我甚至不确定.实际上,产生"scenario"值的位操作会让我感到不必要的容易出错. (2认同)

Gia*_*olo 28

我以前的答案已经是公认的答案,我在这里添加一些我认为既可读又简单的东西,在这种情况下可以用于未来的修改:

从@ZdeslavVojkovic回答(我发现相当不错)开始,我想出了这个:

#include <iostream>
#include <set>

//using namespace std;

int GetScenarioInt(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
    return bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
}
bool IsValidScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
    std::set<int> validScenarios;
    validScenarios.insert(GetScenarioInt(true, true, true, true));
    validScenarios.insert(GetScenarioInt(true, true, true, false));
    validScenarios.insert(GetScenarioInt(true, false, false, false));

    int currentScenario = GetScenarioInt(bValue1, bValue2, bValue3, bValue4);

    return validScenarios.find(currentScenario) != validScenarios.end();
}

int main()
{
    std::cout << IsValidScenario(true, true, true, false) << "\n"; // expected = true;
    std::cout << IsValidScenario(true, true, false, false) << "\n"; // expected = false;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这里看到它

嗯,这是我通常的目标"优雅和可维护"(恕我直言)的解决方案,但实际上,对于OP案例,我之前的"一堆ifs"答案更符合OP要求,即使它不优雅也不可维护.


Sta*_*nny 20

我还想提交另一种方法.

我的想法是将bools转换为整数,然后使用可变参数模板进行比较:

unsigned bitmap_from_bools(bool b) {
    return b;
}
template<typename... args>
unsigned bitmap_from_bools(bool b, args... pack) {
    return (bitmap_from_bools(b) << sizeof...(pack)) | bitmap_from_bools(pack...);
}

int main() {
    bool bValue1;
    bool bValue2;
    bool bValue3;
    bool bValue4;

    unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);

    if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u) {
        //bad scenario
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意该系统如何支持最多32个bool作为输入.替换unsignedwith unsigned long long(或uint64_t)会增加对64个案例的支持.如果您不喜欢if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u),您还可以使用另一种可变参数模板方法:

bool equals_any(unsigned target, unsigned compare) {
    return target == compare;
}
template<typename... args>
bool equals_any(unsigned target, unsigned compare, args... compare_pack) {
    return equals_any(target, compare) ? true : equals_any(target, compare_pack...);
}

int main() {
    bool bValue1;
    bool bValue2;
    bool bValue3;
    bool bValue4;

    unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);

    if (!equals_any(summary, 0b1111u, 0b1110u, 0b1000u)) {
        //bad scenario
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您分享您的替代方法. (3认同)
  • 除了主函数的名称外,我喜欢这种方法:“从bool…到* what * ??” —为什么不显式地显示“ bitmap_from_bools”或“ bools_to_bitmap”? (2认同)

gez*_*eza 17

这是一个简化版本:

if (bValue1&&(bValue2==bValue3)&&(bValue2||!bValue4)) {
    // acceptable
} else {
    // not acceptable
}
Run Code Online (Sandbox Code Playgroud)

当然,请注意,此解决方案比原始解决方案更加模糊,其含义可能更难理解.


更新:评论中的MSalters发现了一个更简单的表达式:

if (bValue1&&(bValue2==bValue3)&&(bValue2>=bValue4)) ...
Run Code Online (Sandbox Code Playgroud)


Yak*_*ont 12

考虑将表格尽可能直接地翻译到您的程序中.根据表格驱动程序,而不是用逻辑模拟它.

template<class T0>
auto is_any_of( T0 const& t0, std::initializer_list<T0> il ) {
  for (auto&& x:il)
    if (x==t0) return true;
  return false;
}
Run Code Online (Sandbox Code Playgroud)

现在

if (is_any_of(
  std::make_tuple(bValue1, bValue2, bValue3, bValue4),
  {
    {true, true, true, true},
    {true, true, true, false},
    {true, false, false, false}
  }
))
Run Code Online (Sandbox Code Playgroud)

这可以直接将您的真值表编码到编译器中.

实例.

您也可以std::any_of直接使用:

using entry = std::array<bool, 4>;
constexpr entry acceptable[] = 
  {
    {true, true, true, true},
    {true, true, true, false},
    {true, false, false, false}
  };
if (std::any_of( begin(acceptable), end(acceptable), [&](auto&&x){
  return entry{bValue1, bValue2, bValue3, bValue4} == x;
}) {
}
Run Code Online (Sandbox Code Playgroud)

编译器可以内联代码,消除任何迭代并为您构建自己的逻辑.同时,您的代码完全反映了您如何解决问题.


And*_*kle 11

我只在这里提供我的答案,就像有人建议显示我的解决方案的评论一样.我要感谢大家的见解.

最后,我选择添加三个新的"场景" boolean方法:

bool CChristianLifeMinistryValidationDlg::IsFirstWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
    return (INCLUDE_ITEM1(pEntry) && 
           !INCLUDE_ITEM2(pEntry) && 
           !INCLUDE_ITEM3(pEntry) && 
           !INCLUDE_ITEM4(pEntry));
}

bool CChristianLifeMinistryValidationDlg::IsSecondWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
    return (INCLUDE_ITEM1(pEntry) &&
            INCLUDE_ITEM2(pEntry) &&
            INCLUDE_ITEM3(pEntry) &&
            INCLUDE_ITEM4(pEntry));
}

bool CChristianLifeMinistryValidationDlg::IsOtherWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
    return (INCLUDE_ITEM1(pEntry) && 
            INCLUDE_ITEM2(pEntry) && 
            INCLUDE_ITEM3(pEntry) && 
           !INCLUDE_ITEM4(pEntry));
}
Run Code Online (Sandbox Code Playgroud)

然后我能够像我这样应用那些我的验证程序:

if (!IsFirstWeekStudentItems(pEntry) && !IsSecondWeekStudentItems(pEntry) && !IsOtherWeekStudentItems(pEntry))
{
    ; Error
}
Run Code Online (Sandbox Code Playgroud)

在我的实时应用程序中,4个bool值实际上是从DWORD有4个编码到其中的值中提取的.

再次感谢大家.


Err*_*ous 11

虽然OP的解决方案就是这样做的,但我没有看到任何答案说明这些情景.

对我来说,最好将每个场景的注释封装到变量名或函数名中.您更可能忽略评论而不是名称,如果您的逻辑在未来发生变化,您更可能更改名称而不是评论.你无法重构评论.

如果您计划在函数之外重用这些场景(或者可能想要),那么创建一个函数来说明它的评估结果(constexpr/ noexcept可选但推荐):

constexpr bool IsScenario1(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && b4; }

constexpr bool IsScenario2(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && !b4; }

constexpr bool IsScenario3(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && !b2 && !b3 && !b4; }
Run Code Online (Sandbox Code Playgroud)

尽可能使这些类方法(如在OP的解决方案中).如果您认为不会重用逻辑,则可以在函数内部使用变量:

const auto is_scenario_1 = bValue1 && bValue2 && bValue3 && bValue4;
const auto is_scenario_2 = bvalue1 && bvalue2 && bValue3 && !bValue4;
const auto is_scenario_3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
Run Code Online (Sandbox Code Playgroud)

编译器很可能会理解,如果bValue1为false,那么所有场景都是假的.不要担心快速,正确和可读.如果您对代码进行概要分析并发现这是一个瓶颈,因为编译器在-O2或更高的位置生成了次优代码,那么请尝试重写它.


hes*_*ieh 9

AC/C++方式

bool scenario[3][4] = {{true, true, true, true}, 
                        {true, true, true, false}, 
                        {true, false, false, false}};

bool CheckScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
    bool temp[] = {bValue1, bValue2, bValue3, bValue4};
    for(int i = 0 ; i < sizeof(scenario) / sizeof(scenario[0]); i++)
    {
        if(memcmp(temp, scenario[i], sizeof(temp)) == 0)
            return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

这种方法是可扩展的,就好像有效条件的数量增加一样,您可以轻松地将更多条件添加到方案列表中.


Mic*_*Łoś 9

很容易注意到前两种情况是相似的 - 它们共享大多数条件.如果你想选择你现在的场景,你可以这样写(这是一个修改过的@ gian-paolo的解决方案):

bool valid = false;
if(bValue1 && bValue2 && bValue3)
{
    if (bValue4)
        valid = true; //scenario 1
    else if (!bValue4)
        valid = true; //scenario 2
}
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
    valid = true; //scenario 3
Run Code Online (Sandbox Code Playgroud)

更进一步,您可以注意到,第一个布尔值必须始终为真,这是一个条目条件,因此您最终可以:

bool valid = false;
if(bValue1)
{
    if(bValue2 && bValue3)
    {
        if (bValue4)
            valid = true; //scenario 1
        else if (!bValue4)
            valid = true; //scenario 2
    }
    else if (!bValue2 && !bValue3 && !bValue4)
        valid = true; //scenario 3
}
Run Code Online (Sandbox Code Playgroud)

更重要的是,你现在可以清楚地看到,bValue2和bValue3有点连接 - 你可以将它们的状态提取到一些具有更合适名称的外部函数或变量(虽然这并不总是容易或合适):

bool valid = false;
if(bValue1)
{
    bool bValue1and2 = bValue1 && bValue2;
    bool notBValue1and2 = !bValue2 && !bValue3;
    if(bValue1and2)
    {
        if (bValue4)
            valid = true; //scenario 1
        else if (!bValue4)
            valid = true; //scenario 2
    }
    else if (notBValue1and2 && !bValue4)
        valid = true; //scenario 3
}
Run Code Online (Sandbox Code Playgroud)

这样做有一些优点和缺点:

  • 条件较小,因此更容易推理它们,
  • 更好地重命名以使这些条件更容易理解,
  • 但是,他们需要了解范围,
  • 而且它更加僵硬

如果您预测上述逻辑会有变化,您应该使用@ gian-paolo提供的更简单的方法.

否则,如果这些条件已经很好地建立,并且是一种永远不会改变的"可靠规则",请考虑我的最后一个代码片段.


gsa*_*ras 7

正如mch所建议的,你可以这样做:

if(!((bValue1 && bValue2 && bValue3) || 
  (bValue1 && !bValue2 && !bValue3 && !bValue4))
)
Run Code Online (Sandbox Code Playgroud)

第一行覆盖两个第一个好案例,第二行覆盖最后一行.

Live Demo,我在哪里玩,它通过你的案件.


Mat*_*att 7

@GianPaolo的精彩答案稍有不同,有些人可能会觉得更容易阅读:

bool any_of_three_scenarios(bool v1, bool v2, bool v3, bool v4)
{
  return (v1 &&  v2 &&  v3 &&  v4)  // scenario 1
      || (v1 &&  v2 &&  v3 && !v4)  // scenario 2
      || (v1 && !v2 && !v3 && !v4); // scenario 3
}

if (any_of_three_scenarios(bValue1,bValue2,bValue3,bValue4))
{
  // ...
}
Run Code Online (Sandbox Code Playgroud)


sho*_*ged 7

每个答案都过于复杂,难以阅读.对此的最佳解决方案是switch()声明.它既可读又简单地添加/修改其他案例.编译器也擅长优化switch()语句.

switch( (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1) )
{
    case 0b1111:
        // scenario 1
        break;

    case 0b0111:
        // scenario 2
        break;

    case 0b0001:
        // scenario 3
        break;

    default:
        // fault condition
        break;
}
Run Code Online (Sandbox Code Playgroud)

您当然可以在case语句中使用常量和OR,以获得更高的可读性.


Gnu*_*iff 6

为清晰起见,我还会使用快捷方式变量.如前所述,方案1等于方案2,因为bValue4的值不会影响这两种方案的真实性.

bool MAJORLY_TRUE=bValue1 && bValue2 && bValue3
bool MAJORLY_FALSE=!(bValue2 || bValue3 || bValue4)
Run Code Online (Sandbox Code Playgroud)

然后你的表达beomes:

if (MAJORLY_TRUE || (bValue1 && MAJORLY_FALSE))
{
     // do something
}
else
{
    // There is some error
}
Run Code Online (Sandbox Code Playgroud)

为MAJORTRUE和MAJORFALSE变量(以及实际上为bValue*变量)赋予有意义的名称对于可读性和维护有很大帮助.


Bil*_*uya 6

关注问题的可读性,而不是具体的"if"语句.

虽然这会产生更多的代码行,但有些人可能会认为它过分或不必要.我建议从特定的布尔值中抽象你的场景是保持可读性的最佳方法.

通过将事物分成类(可以随意使用函数,或者您喜欢的任何其他工具)和可理解的名称 - 我们可以更容易地显示每个场景背后的含义.更重要的是,在具有许多移动部件的系统中 - 更容易维护和加入现有系统(尽管有多少额外代码被调用).

#include <iostream>
#include <vector>
using namespace std;

// These values would likely not come from a single struct in real life
// Instead, they may be references to other booleans in other systems
struct Values
{
    bool bValue1; // These would be given better names in reality
    bool bValue2; // e.g. bDidTheCarCatchFire
    bool bValue3; // and bDidTheWindshieldFallOff
    bool bValue4;
};

class Scenario
{
public:
    Scenario(Values& values)
    : mValues(values) {}

    virtual operator bool() = 0;

protected:
    Values& mValues;    
};

// Names as examples of things that describe your "scenarios" more effectively
class Scenario1_TheCarWasNotDamagedAtAll : public Scenario
{
public:
    Scenario1_TheCarWasNotDamagedAtAll(Values& values) : Scenario(values) {}

    virtual operator bool()
    {
        return mValues.bValue1
        && mValues.bValue2
        && mValues.bValue3
        && mValues.bValue4;
    }
};

class Scenario2_TheCarBreaksDownButDidntGoOnFire : public Scenario
{
public:
    Scenario2_TheCarBreaksDownButDidntGoOnFire(Values& values) : Scenario(values) {}

    virtual operator bool()
    {
        return mValues.bValue1
        && mValues.bValue2
        && mValues.bValue3
        && !mValues.bValue4;
    }   
};

class Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere : public Scenario
{
public:
    Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(Values& values) : Scenario(values) {}

    virtual operator bool()
    {
        return mValues.bValue1
        && !mValues.bValue2
        && !mValues.bValue3
        && !mValues.bValue4;
    }   
};

Scenario* findMatchingScenario(std::vector<Scenario*>& scenarios)
{
    for(std::vector<Scenario*>::iterator it = scenarios.begin(); it != scenarios.end(); it++)
    {
        if (**it)
        {
            return *it;
        }
    }
    return NULL;
}

int main() {
    Values values = {true, true, true, true};
    std::vector<Scenario*> scenarios = {
        new Scenario1_TheCarWasNotDamagedAtAll(values),
        new Scenario2_TheCarBreaksDownButDidntGoOnFire(values),
        new Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(values)
    };

    Scenario* matchingScenario = findMatchingScenario(scenarios);

    if(matchingScenario)
    {
        std::cout << matchingScenario << " was a match" << std::endl;
    }
    else
    {
        std::cout << "No match" << std::endl;
    }

    // your code goes here
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 在某些时候,冗长会开始损害可读性.我觉得这太过分了. (5认同)
  • @JollyJoker我确实在这种特定的情况下表示同意 - 但是,我对OP一直非常一般地命名的方式的感觉是,他们的"真实"代码可能比他们给出的例子复杂得多.真的,我只是想把这个替代品放在那里,因为我是如何为更复杂/更复杂的东西构建它.但是你是对的 - 对于OP的具体例子来说,它过于冗长并且使事情变得更糟. (2认同)

isp*_*iro 5

这取决于他们代表什么.

例如,如果1是一个密钥,23是必须同意的两个人(除非他们同意NOT他们需要第三个人 - 4 - 确认),最可读的可能是:

1 &&
    (
        (2 && 3)   
        || 
        ((!2 && !3) && !4)
    )
Run Code Online (Sandbox Code Playgroud)

按流行要求:

Key &&
    (
        (Alice && Bob)   
        || 
        ((!Alice && !Bob) && !Charlie)
    )
Run Code Online (Sandbox Code Playgroud)

  • 你可能是对的,但使用数字来说明你的观点会减损你的答案.尝试使用描述性名称. (2认同)