3

The output of the following program is "they are not equal", but I'd expect "they are equal" as the three compared variables (x,y, and z) are equal. Why?

#include <iostream>

int main()
{
    int y, x, z;
    y = 3;
    x = 3;
    z = 3;

    if (x == y == z)
    {
        std::cout << "they are equal\n";
    }
    else
    {
        std::cout << "they are not equal\n";
    }
}
YSC
  • 38,212
  • 9
  • 96
  • 149
Snake Eyez
  • 77
  • 5

2 Answers2

10

This is because of the way expression and types are evaluated.

Let's evaluate the leftmost ==

x == y ...

This evaluates to true. Let's rewrite the expression:

//  x == y
if (true   == z) {
    // ...
}

The true is a boolean value. A boolean value cannot be directly compared to an int. A conversion from the boolean to an integer must occur, and the result is 1 (yes, true == 1). Let's rewrite the expression to its equivalent value:

//  true
if (1    == z) {
    //    ^--- that's false
}

But z isn't equal to 1. That expression is false!

Instead, you should separate both boolean expressions:

if (x == y && y == z) {
    // ...
}
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
0

And now some practical C++17 applications. No SFINAE necessary.

//----------------------------------
// constexpr lambda requires C++17
auto eq3 = [] (auto v1, auto v2, auto v3) constexpr -> bool
{
    return ( v1 == v2 ) && ( v2 == v3 );
};

Usage is simple but fully compile time

constexpr auto same_ = eq3(42,42,42);
std::bool_constant< eq3(42,42,42) > twins_ ;

For comparing a whole sequences of values, concept is the same, impementation is a little bit more involved.

template<typename ... T>
constexpr bool all_equal ( const T & ... args_ )  
{
    if ((sizeof...( args_) ) < 2) return true;
    // for non recursive version
    const auto il_ = { args_ ... };
    // compare them all to the first
    auto first_ = *(il_.begin()) ;
    // assumption
    bool rezult_{ true }; 
    for ( auto && elem_ : il_) {
        // yes I know, first cycle compares first_ to itself ...
        rezult_ = rezult_ && ( first_ == elem_ );
        // short circuit-ing
        if (!rezult_) break;
    }
    return rezult_; 
};

"just" a function, compile time, again no variadic template trickery.

    bool_constant< all_equal(42,42,42,42,42,42,42) > same_ ;
    cout << endl << boolalpha <<  same_() ;

    bool_constant< all_equal(42,43,44,45,46,47) > not_same_ ;
    cout << endl << boolalpha <<  not_same_() ;

Mandatory Wandbox is here.

ps: somewhat predictable all_equal does not compile using the very latest CL also known as MSVC or Visual Studio.

Chef Gladiator
  • 902
  • 11
  • 23