Search code examples
c++referencetype-deduction

Confusion on return type deduction with unpacking references


The following code

#include <functional>
#include <tuple>
#include <iostream>

struct Point
{
    int x;
    int y;
};

decltype(auto) memrefs(Point &p)
{
    return std::make_tuple(std::ref(p.x), std::ref(p.y));
}

int main()
{
    Point p;
    auto& [x, y] = memrefs(p);
    x = 1;
    y = 2;
    std::cout << p.x << " " << p.y << std::endl;
    return 0;
}

does not compile. Reported by GCC 8.1.0:

error: cannot bind non-const lvalue reference of type 'std::tuple<int&, int&>&' to an rvalue of type 'std::tuple<int&, int&>'

However, it will compile if I change

auto& [x, y] = memrefs(p);

to

auto [x, y] = memrefs(p)

My question is why? Aren't x and y references?


Solution

  • decltype(auto) memrefs(Point &p);
    

    is

    std::tuple<int&, int&> memrefs(Point &p);
    

    In structured_binding, auto& in auto& [x, y] applies to the "tuple", not to x, y.

    and you cannot have

    std::tuple<int&, int&>& tup = memrefs(p);
    

    but you can have

    std::tuple<int&, int&> tup = memrefs(p);
    

    then x, y refers to the appropriate part of the tuple.