2

Inspired by another question regarding java-script language. Can the expression

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

evaluate to true in C++? (And if so, can it actually be useful?)

mathreadler
  • 447
  • 5
  • 16
  • 2
    Much of the answers there can obviously be trivially modified so that they work in C++. –  Jan 20 '18 at 12:32
  • @hvd : Yes I think so too. But I wonder also if it can be useful with the mechanics of C++. To actually build useful things and not just as a curiosity. – mathreadler Jan 20 '18 at 12:34
  • 3
    The answer very depends on the type of `a`. If `a` is an integral type - never. On the other hand, if `a` is a `class` and comparison operators are overloaded in this way (for whatever it might be good for) - no problem. – Scheff's Cat Jan 20 '18 at 12:35
  • Yes great, that is what I was thinking. How to use it with operator overloading and polymorphism and what can be practically constructed using that. – mathreadler Jan 20 '18 at 12:36
  • Please tell me why you want code that is confusing and reply on side affects? – Ed Heal Jan 20 '18 at 12:40
  • For what it could be useful? For a special arithmetic where comparison only reflects sign? (Hence `a` > 0 => `a == 1 && a == 2 && a == 3`). I don't have such a use case at hand. But I know that in the past I already found use cases which I couldn't imagine before. My imagination/fantasy is too limited sometimes - no tool to justify something as useful or not... – Scheff's Cat Jan 20 '18 at 12:43
  • 2
    The JavaScript post is already a huge waste of time, replicating it in C++ is hardly useful. Having something that behaves completely out of the norm is obviously a code smell. – Passer By Jan 20 '18 at 12:47
  • In C++, if `a` is `volatile`, it is conceivable that it's value will change (by some means invisible to the compiler) between the three consecutive tests for inequality - even if it is a variable of a basic type. The chances of that actually happening are small, and it is probably not a particularly useful effect. – Peter Jan 20 '18 at 13:26
  • @PasserBy sure, unless we hide away all the functionality in a superclass. so the object itself is not altered. but C++ has many ways to do that with template inheritance, especially the later years versions. – mathreadler Jan 20 '18 at 13:27

8 Answers8

10

Yes it can:

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

Then, let a be of type Foo and voila.

Can this actually be useful? I don't really see it being useful no.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
5

Can the expression evaluate to true in C++?

Yes, nothing is impossible...

struct A {
    int x = 0;
};

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

Then:

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

prints meow.

But I have no idea of any practical usage of such weird overloading and, hopefully, will never see such code in production.

Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67
2

Could be somewhat useful.

#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;
}
super
  • 12,335
  • 2
  • 19
  • 29
2

As it was noticed before, this trick could be performed with volatile. This is more honest approach compared to operator changing. Just let us use two threads:

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;
    }
}

Moreover, this code in my case is working well with no volatile declaration. As far as I understand, it should depend on compiler and processor. Maybe someone could correct it, if I'm wrong.

Stanislav
  • 73
  • 8
1

Other things not mentioned yet (source):

  • a might have overloaded operator int(), the operator for implicit conversion to int (instead of operator== as covered by other answers).
  • a might be a preprocessor macro.

Example of the latter:

int b = 0;
#define a ++b
if ((a==1)&&(a==2)&&(a==3))
    std::cout << "aha\n";
M.M
  • 138,810
  • 21
  • 208
  • 365
0

Operator overloading and macros are trivial solutions to such a riddle.

And if so, can it actually be useful?

Well, with some imagination... One possible use case I can think of are unit tests or integration tests in which you want to make sure that your overloaded operator== for some class works correctly and you know for sure that it works incorrectly if it reports equality for different operands when it's not supposed to do that:

class A {
public:
    A(int i);
    bool operator==(int i) const;
    // ...
};

A a(1);

if ((a==1)&&(a==2)&&(a==3)) {
    // failed test
    // ...
}
Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
0

I assume a requirement is a valid program free of undefined behaviour. Otherwise simply introduce something like a data race and wait for the right circumstances to occur.

In a nutshell: Yes, it is possible for user-defined types. C++ has operator overloading, so the related answers from the JavaScript question apply. a must be a user-defined type because we compare against integers and you cannot implement operator overloads where all parameters are built-in types. Given that, a trivial solution could look like:

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

Can something like this be useful? As the question is stated: almost certainly not. There is a strong semantic meaning implied by the operator symbols used in their usual context. In the case of == that’s equality comparison. Changing that meaning makes for a surprising API, and that’s bad because it encourages incorrect usage.

However there are libraries that explicitly use operators for completely different purposes.

  • We have an example from the STL itself: iostream’s usage of << and >>.
  • Another one is Boost Spirit. They use operators for writing parsers in an EBNF like syntax.

Such redefinitions of the operator symbols are fine because they make it perfectly obvious that the usual operator symbols are used for a very different purpose.

besc
  • 2,507
  • 13
  • 10
-1

Just to show my own ideas. I was thinking of some data structure like a stream buffer or a ring buffer.

We can with template inheritance "hide away the operator" and nothing will be altered in the data structure in itself but all checking will be done in the template superclass.

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;
}

In this case the == to an integer could be a short-cut for "is the next packet/element in the stream of this ID number" for example.

mathreadler
  • 447
  • 5
  • 16