【问题标题】:Range-based for loop on unordered_map and references [duplicate]unordered_map 和引用上基于范围的 for 循环
【发布时间】:2018-10-21 11:02:13
【问题描述】:

在 std::unordered_map 上运行基于范围的 for 循环时,循环变量的类型似乎不使用引用类型:

std::unordered_map<int, int> map = { {0, 1}, {1, 2}, {2, 3} };
for(auto&[l, r] : map)
    static_assert(std::is_same_v<decltype(r), int&>);

MSVC 2017、gcc 8.2 和 clang 7.0.0 在这里都报告了一个失败的断言。将此反对 std::vector,其中断言不会失败,正如人们所期望的那样:

std::vector<int> vec = { 1, 2, 3 };
for(auto& r : vec)
    static_assert(std::is_same_v<decltype(r), int&>);

但是,在 MSVC 2017 和 gcc 8.2 上,修改局部变量 r 的循环都会产生明显的副作用:

#include <iostream>
#include <type_traits>
#include <unordered_map>
#include <vector>

int main() {
    std::unordered_map<int, int> a = { {0, 1}, {1, 2}, {2, 3} };
    for(auto[l, r] : a)
        std::cout << l << "; " << r << std::endl;
    for(auto&[l, r] : a) {
        static_assert(std::is_same_v<decltype(r), int>);
        r++;
    }
    std::cout << "Increment:" << std::endl;
    for(auto[l, r] : a)
        std::cout << l << "; " << r << std::endl;
}

这个程序例如会打印(忽略顺序):

0; 1
1; 2
2; 3
Increment:
0; 2
1; 3
2; 4

我错过了什么? 尽管局部变量不是引用类型,但这如何改变地图中的值? 或者更恰当地说,为什么 std::is_same 看不到正确的类型,因为很明显它是一个引用类型? 或者我是否遗漏了一些未定义的行为?

请注意,我确实在不使用结构化绑定的情况下重现了相同的问题,因此我将漂亮的代码保留在这里。 See here for an example

【问题讨论】:

标签: c++ language-lawyer c++17 unordered-map structured-bindings


【解决方案1】:

结构化绑定被建模为别名,而不是“真正的”引用。即使他们可能会在后台使用引用。

想象一下你有

struct X {
    const int first = 0;
    int second;
    int third : 8;
};

X x;
X& y = x;

decltype(x.second) 是什么? intdecltype(y.second) 是什么? int。所以在

auto& [first, second, third] = x;

decltype(second)int,因为secondx.second 的别名。并且third 不会造成任何问题,即使它不允许将引用绑定到位域,因为它是别名,而不是实际引用。

类似元组的情况被设计为与此一致。即使在这种情况下语言必须使用引用,它也会尽力假装这些引用不存在。

【讨论】:

  • 但这是只有编译器才能做的事情?作为用户,我永远不能为变量定义别名,对吧?
  • 这里缺少的是指出auto&amp; 中的&amp; 的作用,如果没有按照OP 预期的那样限定引入的名称:它限定decltype(x) 类型的不可见对象,其成员这些名字指的是。实际上存在该类型的不可见引用,并且新名称引用其中的成员,结果更新它们也更新了x
猜你喜欢
  • 1970-01-01
  • 2016-10-31
  • 2021-08-25
  • 1970-01-01
  • 1970-01-01
  • 2018-12-28
  • 2014-12-06
  • 1970-01-01
  • 2014-01-12
相关资源
最近更新 更多