c++ Auto不适用于结构化绑定

fivyi3re  于 2023-05-30  发布在  其他
关注(0)|答案(2)|浏览(188)

我试图理解自定义类型的结构化绑定在实践中是如何工作的。下面的代码无法编译,但出现错误:

error: cannot bind non-const lvalue reference of type ‘Customer&’ to an rvalue of type ‘Customer

我可能错过了一些基本的理解。如果我将auto替换为auto&,或者将Customer&替换为const Customer&,一切都编译得很好。为什么在错误消息中提到Customer的右值?

#include <iostream>
#include <tuple>

struct Customer
{
    int id = 10;
};

template<>
struct std::tuple_size<Customer> : std::integral_constant<std::size_t, 1> {};

template<>
struct std::tuple_element<0, Customer>
{
    using type = int;
};

template<std::size_t id>
auto get(Customer& customer)
{
    if constexpr (id == 0)
    {
        return customer.id;
    }
}

int main() {
    Customer customer;
    auto [id] = customer; // Ouch, error
    std::cout << id;
}
z9ju0rcb

z9ju0rcb1#

传递给get的对象在本例中被定义为一个xvalue,而不是直接传递给customer
cppreference
结构化绑定声明首先引入一个唯一命名的变量(这里用***e***表示)来保存初始化器的值,如下所示:
[阵列案例]
否则,*e*的定义就像在声明中使用其名称而不是[ identifier-list ]一样。我们使用E来表示表达式e的类型。
对于每个标识符,引入一个类型为“引用std::tuple_element<i, E>::type”的变量:如果其对应的初始化器是左值,则为左值引用,否则为右值引用。第i个变量的初始化式为

  • e.get<i>(),如果查找在E范围内通过类成员访问获取的标识符查找至少找到一个声明,该声明是第一个模板参数为非类型参数的函数模板
  • 否则,get<i>(e),其中get仅通过参数相关查找进行查找,忽略非ADL查找。在这些初始化表达式中,如果实体***e***的类型是左值引用,则e是左值(只有当 ref-qualifier 是&或者它是&&并且初始化表达式是左值时才会发生),否则是一个xvalue(这有效地执行了一种完美的转发),istd::size_t纯右值,<i>总是被解释为模板参数列表。
e0bqpujr

e0bqpujr2#

**TLDR;**基本上,get是在customer的副本(其值类别为xvalue)上调用的,而不是在lvalue customer本身上调用的。

当你使用auto [id] = customer;时,它会捕获customer在一个隐藏变量(又名dummy variable)中,比如e。然后,对get的调用是在e上进行的,e是一个副本,它的值类别为rvalue(在本例中,xvalue是特定的),因为T类型的rvalue不能绑定到T的非常量lvalue引用,我们得到了上述错误。

相关问题