我知道我能做
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;
我仍然想知道确切在何处指定此行为。注意:使用“转发引用”来表示此行为可能正在扩展它,但是我没有一个好名字将
const
的auto&&
推演部分指定为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&&