结构化绑定和转发引用能很好地混合吗?
我知道我可以做到
auto&& bla = something();
根据something
返回值的const
程度,我会为bla
获取不同的类型。
这是否也适用于结构化绑定的情况,例如
auto&& [bla, blabla] = something();
我想是的(结构化绑定搭载在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;
我仍然想知道此行为的确切指定位置。
注意:使用";Forwarding References&Quot;表示此行为可能会夸大它,但我没有一个好的名称来给auto&&
的const
扣减部分(或该问题的模板-T&&
)。
解决方案
是。结构化绑定和转发引用很好地混合在一起?。
一般来说,任何地方?都可以使用auto
,可以使用auto&&
获取不同的含义。特别是对于结构化绑定,它来自[dcl.struct.bind]:
否则,
定义为-ife
由attribute-specifier-seqoptDECL-说明符-序号引用限定符选项
e
初始值设定项;
其中声明从不解释为函数声明,并且声明的其他部分(除声明符id)取自相应的结构化绑定声明。
[dcl.dcl]中对这些部分有进一步的限制:
带有标识符列表的简单声明称为结构化绑定声明([dcl.struct.bind])。decl-Specifier-seq只能包含类型说明符
auto
和cv限定符。初始值设定项的格式应为"=
赋值表达式"、"{
赋值表达式"或"(
赋值表达式)
",其中赋值表达式为数组或非联合类类型。<
综合起来,我们可以分解您的示例:
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();
根据something()
的值类别和类型,使e
成为左值或右值引用,即常量不符合条件。
结构化绑定规则的睡觉跟随在[dcl.struct.bind]中,根据e
的底层类型,something()
是否为左值,e
是否为左值引用。
?有一个警告。对于结构化绑定,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&&
相关文章