12

I have question: What does it mean to return an assignment expression like in my code example? I have an enum, and I have overridden the ++:operator. So it is possible to switch between lights in my short example - but there is a part in the code I dont understand. The code compiles and work fine.

Code:

enum Traficlight
{green, yellow, red };

Traficlight& operator++(Traficlight& t)
{
    switch (t)
    {
    case green: return t = Traficlight::yellow; //Here <--
    case yellow: return t = Traficlight::red; //Here <--
    case red: return t = Traficlight::green; //Here <--
    default:
        break;
    }
}

int main()
{


    Traficlight Trafic = Traficlight::green;
    Trafic++;

    if (Trafic == Traficlight::yellow)
    {
        cout << "Light is Yellow" << endl;
    }

    string in;

    cin >> in;

}

What does the return t = Traficlight::yellow mean, why can't I just return Traficlight::yellow?

Løiten
  • 3,185
  • 4
  • 24
  • 36
Niklas
  • 1,753
  • 4
  • 16
  • 35

5 Answers5

13

In the return instructions, the operator assigns to t which is a reference (modifies it) then returns the value.

That's what an incrementation operator does: modifies & returns reference at the same time so the incremented value can be used in another operation.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • For the sake of clarity 7 years later, this is what an increment operator does as long as it is a *pre*-increment operation (i.e. `++i`). Otherwise, with `i++` we return `i` first without modifying, and then modify the reference. :-) – vmishel Mar 07 '23 at 04:17
8

t = Traficlight::yellow writes Traficlight::yellow into t. The result of that expression is also Traficlight::yellow, so this:

return t = Traficlight::yellow;

is equal to:

t = Traficlight::yellow;
return t;

In the function above, reference to t was received as argument, so changing value of t is in fact relevant.

zvone
  • 18,045
  • 3
  • 49
  • 77
3

Your function receives argument by reference:

Traficlight& operator++(Traficlight& t)

And it is a ++ operator, so semantically it must increment it's operand and then return reference to that operand. So you must do two actions:

// Assign new value to the t
t = Traficlight::yellow;
// Return rusult
return t;

This can be written in one line because assignment operator returns the assigned value.

Alexey Guseynov
  • 5,116
  • 1
  • 19
  • 29
0

It assigns value to t variable (and in your code t is reference type so the change is visible outside), and then return value of t variable.

Andrzej Budzanowski
  • 1,013
  • 11
  • 17
0

The expression Traficlight::yellow would be an rvalue, and your function returns a reference to t after changing t's value, which is an lvalue. Assignment operator= on its own returns a reference to its left argument.

The code is ill-formed, some old compilers consider it IFNDR.

One thing though post-increment operator++ in expression Trafic++ is expected to return value before incrementation and would have different signature, so this implementation is misleading and seems to be mixed up with pre-increment operator++. It actually looks like you're using an old non-conforming compiler which allows use of built-in increment operator on an enum (some ancient Visual Studio?). In this case it's a bug and your operator++ isn't used at all.

Changing signature to Traficlight& operator++(Traficlight& t, int) would make it compile, although behaviour would be non-idiomatic. ++Trafic; also would compile by a standard compiler.

PS. Idiomatic post-increment looks something like this, no reference returned:

Traficlight operator++(Traficlight& t)
{
    switch (t)
    {
    case green: t = Traficlight::yellow; return Traficlight::green;
    case yellow: return t = Traficlight::red; return Traficlight::yellow;
    case red: return t = Traficlight::green; return Traficlight::red;
    default:
        break;
    }
}

++Torch can be used as an lvalue. Torch++ cannot, it is supposed to return the old value of variable. It's easy to remember which signature to use - for unary operators argument goes after the operator. If argument goes before operator, it must be a binary one. Except here the second argument doesn't exist.

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42