rub*_*nvb 15 c++ language-lawyer forwarding-reference c++17 structured-bindings
我知道我能做到
auto&& bla = something();
Run Code Online (Sandbox Code Playgroud)
并且根据const返回值的something不同,我会得到一个不同的类型bla.
这是否也适用于结构化绑定案例,例如
auto&& [bla, blabla] = something();
Run Code Online (Sandbox Code Playgroud)
我猜是这样的(结构化绑定捎带在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;
}
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
我仍然想知道这个行为的确切位置.
注意:使用"转发引用"来表示这种行为可能会延伸它,但是我没有一个好名字来给出const演绎部分auto&&(或模板T&&).
是.结构化绑定和转发参考混合良好†.
在一般情况下,任何地方‡您可以使用auto,你可以使用auto&&来获取不同的含义.具体来说,对于结构化绑定,这来自[dcl.struct.bind]:
否则,
e定义为-if byattribute-specifier-seq opt decl-specifier-seq ref-qualifier opt
einitializer;声明永远不会被解释为函数声明,声明的声明部分以外的声明部分取自相应的结构化绑定声明.
[dcl.dcl]中对这些部分还有进一步的限制:
甲简单声明与一个标识符列表被称为结构化绑定声明([dcl.struct.bind]).该DECL说明符-SEQ应当只包含类型说明符
auto和品种 -qualifiers.的初始值设定应为形式"的=分配表达 ",形式为"{赋值表达式}",或形式为"(赋值表达式)",其中赋值表达式是阵列或不愈合类型的.
把它放在一起,我们可以打破你的榜样:
auto&& [bla, blabla] = something();
Run Code Online (Sandbox Code Playgroud)
声明这个未命名的变量:
auto && e = something();
~~~~ ~~ ~~~~~~~~~~~
decl-specifier-seq initializer
ref-qualifier
Run Code Online (Sandbox Code Playgroud)
行为是从[dcl.spec.auto](具体在这里)派生的.在那里,我们确实对初始化器进行了推论:
template <typename U> void f(U&& );
f(something());
Run Code Online (Sandbox Code Playgroud)
其中auto被取代U,并且&&携带了过来.这是我们的转发参考.如果扣除失败(只有在扣除的情况something()下void),我们的声明就是格式错误.如果成功,我们抓住推断出来U并将我们的声明视为:
U&& e = something();
Run Code Online (Sandbox Code Playgroud)
e根据值的类别和类型,它构成一个左值或右值引用,即const限定为not something().
其余的结构化绑定规则遵循[dcl.struct.bind],基于底层类型e,是否something()是左值,以及是否e是左值引用.
†有一点需要注意.对于结构化绑定,decltype(e)始终是引用的类型,而不是您可能期望的类型.例如:
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!
Run Code Online (Sandbox Code Playgroud)
我传递的tuple是一个左值,你希望它作为左值引用传递它的底层元素,但它们实际上是转发的.这是因为decltype(a)它只是int(引用的类型),而不是int&(a行为的有意义的方式).要记住的事情.
‡我可以想到两个地方不是这样的.
在trailing-return-type声明中,您必须使用just auto.你不能写,例如:
auto&& foo() -> decltype(...);
Run Code Online (Sandbox Code Playgroud)
我可以想到的另一个地方可能不是这种情况,它是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&&
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
365 次 |
| 最近记录: |