余国良*_*余国良 3 c++ lambda decltype language-lawyer c++17
#include <iostream>\n#include <type_traits>\n\nint main(){\n\n int i = 1;\n int& j = i;\n\n auto f2 = [j = j]() {\n std::cout\n << std::is_same_v<decltype(j), int&>\n << std::is_same_v<decltype((j)), int&>\n << std::is_same_v<decltype((j)), const int&>;\n };\n \n auto f3 = [=]() {\n std::cout\n << std::is_same_v<decltype(j), int&>\n << std::is_same_v<decltype((j)), int&>\n << std::is_same_v<decltype((j)), const int&>;\n };\n\n f2();\n f3();\n}\nRun Code Online (Sandbox Code Playgroud)\n以下输出是c++17标准的结果
\n| 海湾合作委员会 | 铛 | 微软 |
|---|---|---|
| 001 | 001 | 010 |
| 110 | 101 | 101 |
或者所有的编译器都是错误的\xef\xbc\x9f
\n铿锵是正确的;Clang 给出的结果符合P0588R1引入的措辞,该措辞在 C++17 发布后被接受,但具有 DR 状态,这意味着建议实现将 P0588R1 之前的原始规范视为起草不正确,并且即使在 C++17 模式及更早版本中,P0588R1 中的规则也应该由实现应用。
P0588R1 中的以下示例说明了规则在与第二个示例非常相似的示例中的应用f3:
void f() {
float x, &r = x;
[=] {
decltype(x) y1; // y1 has type float
decltype((x)) y2 = y1; // y2 has type float const& because this lambda is not mutable and x is an lvalue
decltype(r) r1 = y1; // r1 has type float&
decltype((r)) r2 = y2; // r2 has type float const&
};
}
Run Code Online (Sandbox Code Playgroud)
在您的示例中,您拥有引用j而不是引用r,但除此之外,它是相同的。decltype(j)故应如此,int&而decltype((j))应如此const int&。
详细来说,因为decltype(j)和decltype((j))不是 的 odr-uses j,它们表示封闭范围中的原始实体。j( lambda 内部没有存储 的副本,因为 lambda 没有 odr-use j;但即使 lambda 使用了 odr-usej并因此创建了它的副本,非 odr-uses 也j不会引用该副本。 ) 然而,令人困惑的是,lambda 内部的类型不一定是所表示的实体的类型。相反,为了确定 的类型,我们考虑假设的 odr 使用; 然后,我们将类型从假设的成员访问表达式的类型转换为该假设的副本。jjjj
在 的情况下decltype(j),因为j没有括号,忽略表达式decltype的类型,并给出表示实体的声明类型;这是变量的声明类型。在 中,因为带有括号,因此忽略 的声明类型,并查看表达式的类型和值类别。现在,假设的 odr 使用将导致在闭包类型中声明一个成员,但对该成员的假设成员访问表达式将给出类型的左值,因为 lambda 是不可变的。因此,是。int&jdecltype((j))jdecltypej jjintconst intdecltype((j))const int&
现在,让我们将这些规则应用到 的情况f2。这就是有点棘手的地方,因为你有一个init-capture。init -capture实际上引入了一个新名称j,该名称隐藏j了main. 这个新名称表示闭包类型的成员,其类型的确定就像您编写的一样
auto j = j;
Run Code Online (Sandbox Code Playgroud)
除了第一个 的作用域直到lambda-introducerj的右方括号之后才开始,因此第二个引用了属于 的。jjmain
现在,j在 lambda 主体中的任何提及,无论是否为 odr-use,都表示j由init-capture声明。即已j声明类型int,也是decltype(j)如此int。对于decltype((j)),我们再次考虑一个表示成员的成员访问表达式j;该成员访问表达式将再次是类型的左值const int,因此decltype((j))也是const int&。
| 归档时间: |
|
| 查看次数: |
114 次 |
| 最近记录: |