将一个变量与一系列数值进行比较

14

在数学中,符号 18 < age < 30 表示年龄必须在18到30之间。是否可以在if语句中使用这种符号呢?例如,我尝试执行以下代码:

if(18 < age < 30)

我得到了奇怪的输出,所以它并不完全正确。有没有办法解决这个问题,或者我必须重新写代码?

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

1
你的代码有问题:如果年龄等于65怎么办?你执行blah,根据你的描述,这不是你所期望的。 - tibur
7个回答

23

您可以这样做:

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

2
你说得对。可以提到 if( 18 < age < 30) 是一个合法的 C++ 表达式,并解释它将如何被评估。 - John Dibling
5
出于安全原因,我想要加上额外的括号。如果 ((18 < 年龄) && (30 > 年龄))。 - Manoj R
2
运算符 <&& 之前被计算。因此不需要使用额外的括号。 - tibur
4
@tibur,尽管如此,这使得代码更易于阅读,并更易于使用vim的ci(进行修改 :) - Alex B
3
我同意ManoJ R的观点并支持添加括号,但我会这么做是为了提高可读性。 - Martin York
显示剩余2条评论

21

没有人回答您的代码出了什么问题,所以让我来分析一下。

考虑这个语句:bool result = 18 < age < 30;

我们想要评估右侧表达式:18 < age < 30

这个表达式中有两个操作符,并且它们相同,因此它们具有相同的优先级,在这种情况下,它们从左到右进行评估。因此,该表达式等价于:

(18 < age) < 30

让我们首先检查左侧的表达式:18 < age,它产生一个布尔值,可以是true或false,通常分别表示为整数值1或0。因此,该表达式可以总结为:

{0,1} < 30

这个条件始终为真。

因此,如果使用 assert(18 < age < 30);,它永远不会出错。

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


6
一些模板代码可以帮助解决这个问题:
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)) { /****/ }

非常有用的代码片段,考虑在具有重载运算符的类之间使用它。 - Vinícius

3
“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< 使用右手边的值创建一个新的 Weird 对象,并在假设您有效地将一组比较与起来的情况下更新布尔状态。如果你真的想搞乱,你可以在C++中支持各种各样的东西,比如说为了好玩尝试 "x == 6 || 3 || 56" ...?

你尝试过成功构建/运行那些代码吗?我尝试了类似的东西,但在重载比较运算符时遇到了语言限制的问题。它们应该始终返回布尔值,这是我没有预料到的。这可能会在未来的C++版本中得到修复,我希望它能尽快解决。 - acegs
有史以来最好的黑客技巧,+1 - Ayberk Özgür

1

你可以将一个布尔表达式写成

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

像上面这样的表达式可以在任何需要布尔表达式的地方使用,例如(但不限于):

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

或者

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

请注意,上述表达式使用了operator &&短路求值

如果您习惯将rvalue放在运算符的左侧,那么为什么不对(age < 30)也这样做呢? - Chubsdad
我更喜欢按照数字在数轴上的顺序编写数字比较。http://en.wikipedia.org/wiki/Number_line - Arun
我不同意上述表达式“使用短路评估”的观点;它们并不依赖于这种行为。 - Oliver Charlesworth
也许我错了,但我认为如果年龄这个变量的值使得第一个表达式 (18 < age)false,那么第二个表达式就不会被计算。 - Arun
你是正确的,但是由于表达式都没有任何副作用(假设age要么是基本类型,要么是一个重载了operator<的类),所以这完全不相关! - Oliver Charlesworth

0

或者自己编写一组能够实现此功能的好函数

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

为了适应所有类型的边界(包括/不包括)

(不要用于浮点数)

在C++0x中,您可以使用“delete”关键字来禁用函数重载,例如<float/double>,从而允许或禁止所有其他可能性。


0

我不知道有没有办法完全按照你的要求做,但通常的方法是:

使用 and 运算符

if (age > 18 && age <30)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接