Why copy of a member is returned rather than reference?

77 Views Asked by At

According to cppreference member of an object which is lvalue is also an lvalue:

The following expressions are lvalue expressions:

a.m, the member of object expression, except where m is a member enumerator or a non-static member function, or where a is an rvalue and m is a non-static data member of object type;

Consider an example program with a custom class Test which is only a wrapper on int with additional prints in relevant places. In addition, there is a standalone function get which takes universal reference to T and returns its member using decltype(auto) rules.

#include <iostream>

struct Test 
    {
        int member;
        explicit Test(int member): member(member) { std::cout << "Ctor" << std::endl; }
        Test(const Test& other): member(other.member) { std::cout << "Copy ctor" << std::endl; }
        Test(Test&& other) noexcept: member(other.member) { std::cout << "Move ctor" << std::endl; }
        Test& operator=(const Test& other) { member = other.member; std::cout << "Copy =" << std::endl; return *this; }
        Test& operator=(Test&& other) { member = other.member; std::cout << "Move =" << std::endl; return *this; }
        ~Test() { std::cout << "Dtor" << std::endl; }
    };
    
    template <typename T>
    decltype(auto) get(T&& obj)
    {   
        std::cout << "Is obj lvalue ref? " << std::is_lvalue_reference_v<decltype(std::forward<T>(obj))> << std::endl;
        return std::forward<T>(obj).member;
    }
    
    int main()
    {
        Test test{1234};
        auto&& ret = get(test);
        ret = 5678;
        std::cout << "test.member is equal to " << test.member << std::endl;
        return 0;
    }

To my understanding decltype(auto) deduces the type of an expression as follows:

  1. For a prvalue it yields its type
  2. For an lvalue it yields reference
  3. For an xvalue it yields rvalue reference

But the output of the program is as follows:

Ctor
Is obj lvalue ref? 1
test.member is equal to 1234
Dtor

Assignment ret = 5678 inside the main function does not change the value of the member inside the test object so the copy has to be done. Looks my understanding is not correct.

0

There are 0 best solutions below