我试图理解自定义类型的结构化绑定在实践中是如何工作的。下面的代码无法编译,但出现错误:
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;
}
2条答案
按热度按时间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(这有效地执行了一种完美的转发),i
是std::size_t
纯右值,<i>
总是被解释为模板参数列表。e0bqpujr2#
**TLDR;**基本上,
get
是在customer
的副本(其值类别为xvalue
)上调用的,而不是在lvaluecustomer
本身上调用的。当你使用
auto [id] = customer;
时,它会捕获customer
在一个隐藏变量(又名dummy variable)中,比如e
。然后,对get
的调用是在e
上进行的,e
是一个副本,它的值类别为rvalue(在本例中,xvalue是特定的),因为T
类型的rvalue不能绑定到T
的非常量lvalue引用,我们得到了上述错误。