c++value-categories

Can I run different logic for a function returning reference depending on whether it's used as lvalue or rvalue?


Consider the following code:

#include <iostream>

struct Foo {
  int x;
  int& val() { 
    return x; 
  }
};

int main() {
  Foo foo;
  foo.val() = 2;
  int y = foo.val();
}

In the main function, foo.val() is sometimes used as lvalue and sometimes as rvalue. I would like to to put logic inside the definition of val() function depending on how it's being used. Is that possible?


Solution

  • In the main function, foo.val() is sometimes used as lvalue and sometimes as rvalue. I would like to to put logic inside the definition of val() function depending on how it's being used. Is that possible

    There is no straightforward way to do what you want.

    However, you could wrap the integer inside a wrapper class and use the conversion operator operator int& and operator= to achieve what you want:

    #include <iostream>
    #include <functional>
    
    class Foo {
        template <typename T>
        struct Wrapped {
            std::reference_wrapper<T> x;
            Wrapped(Wrapped<T> const& rhs) : x(std::ref(rhs.x.get())) {
                std::cout << "rvalue" << std::endl;
            }
            Wrapped(T& x) : x(std::ref(x)) {}
            Wrapped<T>& operator=(T const& a) {
                std::cout << "lvalue" << std::endl;
                x.get() = a;
                return *this;
            }
            operator T&() {
                std::cout << "rvalue" << std::endl;
                return x.get();
            }
        };
        Wrapped<int> x_w = Wrapped<int>(x);
    public:
        int x;
        Wrapped<int>& val() {
            return x_w; 
        }
    };
    
    int main() {
        Foo foo;
        foo.val() = 2;      // lvalue
        int y = foo.val();  // rvalue
        auto z = foo.val(); // rvalue
    }