【问题标题】:Comparing a variable to a range of values将变量与一系列值进行比较
【发布时间】:2010-09-30 12:55:17
【问题描述】:

在数学中,符号18 < age < 30 表示年龄必须介于值18 和30 之间。是否可以在if 语句中使用这种符号?例如,我尝试过执行

if(18 < age < 30)

我得到了奇怪的输出,所以它不太正确。有没有办法做到这一点,或者我只需要写

if(age > 18) /*blah*/;
else if(age < 30) /*same blah*/;

【问题讨论】:

  • 您的代码错误:如果年龄等于 65 岁怎么办?你执行 blah,根据你的描述,这不是你所期望的。

标签: c++


【解决方案1】:

没有人回答你的代码到底发生了什么,所以让我把它分开。

考虑单个语句:bool result = 18 &lt; age &lt; 30;

我们要计算右边的表达式:18 &lt; age &lt; 30

这个表达式中有两个运算符,由于它们是相同的,所以它们都具有相同的优先级,在这种情况下,它们是从左到右计算的,因此表达式等价于:

(18 < age) < 30

所以让我们首先检查左边的成员:18 &lt; age,它产生一个布尔值,为真或假,通常表示为整数值,分别为 1 或 0。因此表达式可以总结为:

{0,1} < 30

这总是正确的。

因此,如果您使用assert(18 &lt; age &lt; 30);,它绝不会适得其反。

这种整数(和浮点)内置类型之间的隐式转换真的很烦人......

【讨论】:

    【解决方案2】:

    你可以这样做:

    if (18 < age && age < 30) /*blah*/;
    

    【讨论】:

    • 你明白了。可能会提到if( 18 &lt; age &lt; 30) 是一个合法的 C++ 表达式,并解释如何评估它。
    • 为了安全起见,我想加上额外的括号。 if((18 年龄))
    • 运算符&lt;&amp;&amp; 之前进行评估。所以没有必要使用额外的括号。
    • @tibur,它仍然使代码更易于阅读,并且对 vim 的ci( 更具延展性:)
    • 我支持 ManoJ R 添加大括号。但我会这样做是为了可读性。
    【解决方案3】:

    一些模板代码可以在这里提供帮助:

    template <int min, int max> class range {
      static bool contains(int i) { return min <= i  && i < max; } // In C++, ranges usually are half-open.
    };
    
    int age = 23;
    if (range<18,30>::contains(age)) { /****/ }
    

    【讨论】:

    • 非常有用的一段代码,考虑在具有重载运算符的类之间使用它
    【解决方案4】:

    是否可以在 if 语句中使用这种表示法?

    是的,可能。

    理想,几乎永远不会:程序员假定其他答案中描述的行为将始终适用,因此,如果您大幅更改评估顺序和表达式的含义,那么它真的会让他们非常困惑,并且迟早会导致悲伤.如果您有一个非常小的项目,员工很少,并且他们基本上希望在 C++ 中创建一种特定于领域的语言,使用这种表示法,领域的表示法实际上更具可读性和熟悉性(也许他们是数学家而不是程序员) ),那么您可能在极端情况下考虑像我在下面介绍的那样,尽管它仍然可能会造成麻烦。

    几年前我已经将这种事情作为探索性练习来实施。如果您希望这样做但需要帮助开始:在我的脑海中(即无疑是越野车),请考虑:

    struct Weird
    {
        Weird(int n) : n_(n), b_is_meaningful_(false) { }
        Weird(int n, bool b) : n_(n), b_is_meaningful_(true), b_(b) { }
    
        int n_;
    
        bool b_is_meaningful_;
        bool b_;
    };
    
    Weird operator<(Weird lhs, Weird rhs)
    {
        if (lhs.b_is_meaningful_)
            if (!lhs.b_) // effectively, anding with something already known false...
                return Weird(rhs.n_, false);
        return Weird(rhs.n_, lhs.n_ < rhs.n_);
    }
    

    基本上,你可以破解它,直到你可以:

    Weird x = 10;
    assert(6 < x < 20 < 30 < Weird(80));
    

    在每个点上,operator&lt; 都会创建一个新的 Weird 对象,其右侧 (rhs) 值,同时更新布尔状态,假设您有效地将一组比较组合在一起。如果你真的想弄得一团糟,你可以在 C++ 中支持各种各样的东西,你可能会说“x == 6 || 3 || 56”来好玩...?

    【讨论】:

    • 您是否尝试过成功构建/运行这些代码?我已经尝试过类似的方法,但在重载比较运算符时我仍然遇到语言限制的问题。他们应该总是返回我没想到的 bool。它可能会修复未来版本的 c++,我希望它会更快。
    • 有史以来最好的黑客,+1
    【解决方案5】:

    你可以写一个布尔表达式为

    ((18 < age) && (age < 30))
    

    只要可以接受布尔表达式,就可以使用上述表达式,例如(但不限于):

    if((18 < age) && (age < 30)) { ... }
    

    bool age_in_range = ((18 < age) && (age < 30));
    

    请注意,上面的表达式使用short-circuit evaluationoperator &amp;&amp;

    【讨论】:

    • 如果你习惯将右值放在运算符的左侧,为什么不也(年龄
    • 我更喜欢按照它们在数字行上的顺序来编写数字的比较。 en.wikipedia.org/wiki/Number_line
    • 我不同意上述表述“使用短路评估”的观点;他们不依赖这种行为。
    • 可能是我错了,但我认为如果年龄是这样的,第一个表达式(18 &lt; age)false,那么第二个表达式不会被评估。
    • 你是对的,但由于这两个表达式都没有任何副作用(假设age 是基本类型或具有operator&lt; 的合理重载的类),这完全无关紧要!
    【解决方案6】:

    我不知道完全按照你的要求做,但正常的方法是

    使用 and 运算符

    如果(年龄 > 18 && 年龄

    【讨论】:

      【解决方案7】:

      或者给自己写一组很好的函数来做这个

      template <typename type>
      bool in_range_[none|both|low|high]<type>( value, min, max )
      

      迎合包括/不包括的所有类型的边界

      (不要将它用于浮点)

      在 C++0x 中,您可以使用“delete”关键字来允许和禁止所有其他可能性,该关键字禁用重载函数,例如

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多