来自 std::tuple 的引用绑定类型

Type of reference binding from std::tuple

这里a的类型是什么?

#include <iostream>
#include <tuple>

using namespace std;

int main()
{
    float x{};
    std::tuple<int> tpl( x );
    auto& [ a ] = tpl;
    static_assert( std::is_same_v< decltype( a ), int> );
    //static_assert( std::is_same_v< decltype( a ), int&> );
}

根据标准 11.5/3:

[...] Given the type Ti designated by std::tuple_element<i, E>::type, variables are introduced with unique names ri of type “reference to Ti” initialized with the initializer (11.6.3), where the reference is an lvalue reference if the initializer is an lvalue and an rvalue reference otherwise. Each vi is the name of an lvalue of type Ti that refers to the object bound to ri; the referenced type is Ti.

这里,i 是第一个元素 (int) 的 0,Estd::tuple<int>,所以 Ti 的类型是 std::tuple_element<0, std::tuple<int>>::type,即 int。此外 ri(在我们的例子中是 a)具有类型 "reference to Ti",即左值引用 int&,而不仅仅是 int。 那句话有什么问题,为什么编译器 clang 和 gcc 都推导出 int 类型?

备注

the referenced type is Ti.

对于结构化绑定,decltype 生成引用类型 ([dcl.type.decltype]):

if e is an unparenthesized id-expression naming a structured binding, decltype(e) is the referenced type as given in the specification of the structured binding declaration;

变量r<sub>0</sub>的类型确实是int&。但是 v<sub>0</sub>,这里叫做 a,是不同的东西,结构化绑定的名字,从技术上讲不是变量完全不同,只是一种不同的名称。

所以我们需要看decltype的描述,在[dcl.type.decltype]:

For an expression e, the type denoted by decltype(e) is defined as follows:

  • if e is an unparenthesized id-expression naming a structured binding, decltype(e) is the referenced type as given in the specification of the structured binding declaration;

所以这里的“引用类型”就是 int.

当然,decltype((a)) 是我们预期的 int&。没有双括号的名称上的 decltype 用于找出名称是如何“声明”的,而不是名称的行为方式,因此 decltype(a) “应该”是一回事并不明显,因为a 没有正常的声明。虽然给定 std::tuple<int, int&> t{0, n}; auto& [a, b] = t; 可能有点用处,但我们有 decltype(a)intdecltype(b)int&.