(a==1)&&(a==2)&&(a==3) 的计算结果为 true 吗?(它有用吗?

Can (a==1)&&(a==2)&&(a==3) evaluate to true? (and can it be useful?)

本文关键字:true 有用 计算 结果      更新时间:2023-10-16

灵感来自另一个关于java脚本语言的问题。可以表达

(a==1)&&(a==2)&&(a==3)

评估为真C++?(如果是这样,它真的有用吗?

是的,它可以:

class Foo
{
public:
bool operator==(int a)
{
return true;
}
};

然后,让a属于Foo型,瞧。

这真的有用吗?我真的不认为它有用不。

表达式

的计算结果可以在C++中为 true 吗?

是的,没有什么是不可能的...

struct A {
int x = 0;
};
bool operator==(A& a, int num) {
return ++a.x == num;
}

然后:

if ((a == 1) && (a == 2) && (a == 3)) {
std::cout << "meow" << std::endl;
}

打印meow.

但是我不知道这种奇怪的重载有任何实际用途,希望永远不会在生产中看到这样的代码。

可能有些用处。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Foo {
std::vector<int> v = {1,2,3};
};
bool operator==(const Foo& foo, int i) {
return std::any_of(foo.v.begin(), foo.v.end(), [=](int v){ return v == i; });
}
int main() {
Foo a;
if (a==1 && a==2 && a==3)
cout << "Really??" << endl;
return 0;
}

正如之前注意到的那样,这个技巧可以用volatile来执行。与更换操作员相比,这是更诚实的方法。让我们使用两个线程:

volatile int a;
void changingValue(){
std::srand(unsigned(std::time(0)));
while (true) {
a = (rand() % 3 + 1);
}
}
void checkingValue(){
while (true) {
if (a == 1 && a == 2 && a == 3) {
std::cout << "Good choice!" << std::endl;
}
}
}
int main() {
std::thread changeValue = std::thread(changingValue);
changeValue.detach();
std::thread checkValue = std::thread(checkingValue);
checkValue.detach();
while (true){
continue;
}
}

此外,在我的情况下,这段代码运行良好,没有volatile声明。据我了解,它应该取决于编译器和处理器。如果我错了,也许有人可以纠正它。

其他尚未提及的事情(来源):

  • a可能重载了operator int(),用于隐式转换为int运算符(而不是其他答案所涵盖的operator==)。
  • a可能是预处理器宏。

后者的例子:

int b = 0;
#define a ++b
if ((a==1)&&(a==2)&&(a==3))
std::cout << "ahan";

运算符重载和宏是解决此类谜语的微不足道的解决方案。

如果是这样,它真的有用吗?

好吧,有一些想象力...我能想到的一个可能的用例是单元测试或集成测试,在这些用例中,您希望确保某些类的重载operator==正常工作,并且如果它报告不同操作数的相等性,您肯定知道它工作不正确,而不应该这样做:

class A {
public:
A(int i);
bool operator==(int i) const;
// ...
};
A a(1);
if ((a==1)&&(a==2)&&(a==3)) {
// failed test
// ...
}

我假设需求是一个没有未定义行为的有效程序。否则,只需引入数据竞赛之类的东西,然后等待合适的情况发生。

简而言之:是的,对于用户定义的类型是可能的。C++具有运算符重载,因此 JavaScript 问题中的相关答案适用。a必须是用户定义类型,因为我们与整数进行比较,并且您无法实现所有参数都是内置类型的运算符重载。鉴于此,一个简单的解决方案可能如下所示:

struct A {}
bool operator==(A, int) { return true; }
bool operator==(int, A) { return true; }

这样的东西有用吗?正如问题所述:几乎可以肯定不是。在其通常上下文中使用的运算符符号隐含了强烈的语义含义。在==的情况下,这就是相等比较。改变这个含义会产生一个令人惊讶的API,这很糟糕,因为它鼓励了不正确的使用。

但是,有些库显式使用运算符用于完全不同的目的。

  • 我们有来自 STL 本身的一个例子:iostream 对<<>>的使用。
  • 另一个是提升精神。他们使用运算符以类似 EBNF 的语法编写解析器。

对运算符符号的这种重新定义很好,因为它们非常明显地表明,通常的运算符符号用于非常不同的目的。

只是为了展示我自己的想法。我在想一些数据结构,如流缓冲区或环形缓冲区。

我们可以通过模板继承"隐藏运算符",数据结构本身不会改变任何内容,但所有检查都将在模板超类中完成。

template<class C>
class Iterable{
C operator==(int a);
public:
Iterable(){pos = 0;}
int pos;
};
template<class C>
class Stream : public Iterable<Stream<C>>{
public:
Stream(C a){ m[0] = a; }
C m[32];
int operator==(int a){
return (m[this->pos++]==a);  }
};
int main(){
Stream<int> a(1);
a.m[0] = 1;    a.m[1] = 3;    a.m[2] = 2;
if(a==1 && a==3 && a==2)
std::cout<<"Really!?"<<std::endl;
return 0;
}

例如,在这种情况下,整数的 == 可能是"是此 ID 号流中的下一个数据包/元素"的快捷方式。