3

I learning about references and value categories because the latter are mentioned in some C++ errors.

I have a function, referenceToDouble that takes in references to double. From watching this video on value categories, I believe that left and right below are lvalue references to double.

In main when I make variables a and b of type double, I don't get an error. Code below shows a and b of type float which gives me an error.

#include <cassert>

double referenceToDouble(double& left, double& right) {
    if (left >= right) {
        right = left;
    }
    else {
        left = right;
    }

    return left;
}

int main() {
    float a = 55.5;
    float b = 55.5;

    assert(55.5 == referenceToDouble(a, b));
}

When I switch the data type of a and b to float, I get this error.

checkReferences.cpp: In function 'int main()':
checkReferences.cpp:18:35: error: cannot bind non-const lvalue reference of type 'double&' to an rvalue of type 'double'
   18 |  assert(55.5 == referenceToDouble(a, b));
      |                                   ^
checkReferences.cpp:3:34: note:   initializing argument 1 of 'double referenceToDouble(double&, double&)'
    3 | double referenceToDouble(double& left, double& right) {
      |                          ~~~~~~~~^~~~

My questions are:

  • where is the rvalue coming from?

  • Is there a temporary variable that contains the double value of a that was cast from float? And is this temporary then the rvalue?

  • Or is the error referring to the 55.5 which is a literal and therefore an rvalue?

  • Is the return type not involved here? I think it isn't because this is a return by value and not by reference.

I tried reading the answer to this question that had a similar error but I wasn't able to dispel my doubts. I also think I know what the solution (use double) is but I am trying to understanding what is going on under the hood.

heretoinfinity
  • 1,528
  • 3
  • 14
  • 33
  • I think this boils down to a question about how your particular compiler warnings are worded and how your compiler works, because when I try Clang 13.0.0 or GCC 11.2 on https://godbolt.org, there is no mention of a `double` rvalue. What particular compiler are you using? – David Grayson Dec 30 '21 at 01:48
  • 1
    @DavidGrayson Are you sure? https://godbolt.org/z/T9zYrvo17 – Retired Ninja Dec 30 '21 at 01:54
  • Indeed, when I click on your link it says "value of type 'float'" and does not say "rvalue of type 'double'". – David Grayson Dec 30 '21 at 01:56
  • I am using `g++` more specifically `g++ (GCC) 9.3.1 20200408` – heretoinfinity Dec 30 '21 at 02:14

1 Answers1

2

Is there a temporary variable that contains the double value of a that was cast from float? And is this temporary then the rvalue?

Yes. left and right with type double& can't bind to floats directly. They have to be converted to doubles firstly, which are temporaries (rvalues) and can't be bound to lvalue-reference to non-const.

If you change the type of left and right to const double& then it'll work fine. The converted double temporaries (rvalues) could be bound to lvalue-reference to const.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405