我知道我能做

auto&& bla = something();
并根据const的返回值的something的正确性,我将得到一种不同的bla类型。
这在结构化绑定(bind)的情况下是否也有效?
auto&& [bla, blabla] = something();
我猜是这样(结构绑定(bind)绑定(bind)在auto初始化程序上,其行为是这样的),但是我找不到确定的答案。
更新:初步测试似乎达到了我的期望(正确得出const的本质):
#include <tuple>

using thing = std::tuple<char, int*, short&, const double, const float&>;

int main()
{
    char c = 0;
    int i = 1;
    short s = 2;
    double d = 3.;
    float f = 4.f;

    thing t{c, &i, s, d, f};

    auto&& [cc, ii, ss, dd, ff] = t;

    c = 10;
    *ii = 11;
    ss = 12;
    dd = 13.;
    ff = 14.f;
}
Live demo,如果auto&&正在执行其工作,则会产生我所期望的错误:
main.cpp: In function 'int main()':
main.cpp:20:10: error: assignment of read-only reference 'dd'
     dd = 13.;
          ^~~
main.cpp:21:10: error: assignment of read-only reference 'ff'
     ff = 14.f;
我仍然想知道确切在何处指定此行为。
注意:使用“转发引用”来表示此行为可能正在扩展它,但是我没有一个好名字将constauto&&推演部分指定为T&&(或模板ojit_code)。

最佳答案

是。结构化绑定(bind)和转发引用混合得很好†。
通常,在任何地方‡都可以使用auto,可以使用auto&&获得不同的含义。特别是对于结构化绑定(bind),它来自[dcl.struct.bind]:

[dcl.dcl]中对这些部分有进一步的限制:

放在一起,我们可以分解您的示例:

auto&& [bla, blabla] = something();
声明这个未命名的变量:
auto               && e = something();
~~~~               ~~     ~~~~~~~~~~~
decl-specifier-seq        initializer
                   ref-qualifier
该行为是从[dcl.spec.auto](特别是here)派生的。在那里,我们对初始化程序进行推导:
template <typename U> void f(U&& );
f(something());
此处auto替换为U,并且&&继续执行。这是我们的转发引用。如果推导失败(仅当something()void时才可以),则我们的声明格式错误。如果成功,我们将获取推导的U并将声明视为如下:
U&& e = something();
根据e的值类别和类型,使something()成为左值或右值引用,即const合格,不适合const。
其余结构化绑定(bind)规则基于e的基础类型,something()是否为左值以及e是否为左值引用,遵循[dcl.struct.bind]。

†附带警告。对于结构化绑定(bind),decltype(e)始终是referenced type,而不是您可能期望的类型。例如:
template <typename F, typename Tuple>
void apply1(F&& f, Tuple&& tuple) {
    auto&& [a] = std::forward<Tuple>(tuple);
    std::forward<F>(f)(std::forward<decltype(a)>(a));
}

void foo(int&&);

std::tuple<int> t(42);
apply1(foo, t); // this works!
我将tuple传递为左值,您希望将其基础元素作为左值引用传递,但实际上它们已被转发。这是因为decltype(a)只是int(引用的类型),而不是int&(a表现的有意义的方式)。要记住的事情。
‡我可以想到有两个地方并非如此。
在尾随返回类型声明中,必须仅使用auto。您不能写,例如:
auto&& foo() -> decltype(...);
我可以想到的唯一其他地方可能是Concepts TS的一部分,您可以在更多地方使用auto来推断/约束类型。我认为,在那里,当您要推导的类型不是引用类型时使用转发引用会格式错误:
std::vector<int> foo();
std::vector<auto> a = foo();   // ok, a is a vector<int>
std::vector<auto&&> b = foo(); // error, int doesn't match auto&&

07-24 09:46
查看更多