为什么我可以将 std::map 的键传递给需要非常量的函数?

Why can I pass the key of std::map to a function that expects non-const?

根据std::mapdocumentation,它把键值对存储在std::pair<const Key, Value>中,所以map中的键是const。

现在假设我有一个 std::map,其中键是指向某些对象的指针。

struct S {};
struct Data {};
using MyMap = std::map<S*, Data>;

我们还假设有一个函数 foo 接受 S* 参数。

void foo(S* ptr) { /* modify the object (*ptr) */ }

现在,问题是:当我使用基于范围的 for 循环遍历 MyMap 时,我能够将地图元素键传递给 foo:

MyMap m = getMyMapSomehow();
for (auto elem : m)
{
    static_assert(std::is_const<decltype(elem.first)>::value, "Supposed to be `const S*`");
    foo(elem.first); // why does it compile?
}

所以,即使我的 static_assert 成功了(所以我假设 elem.first 的类型是 const S*),对 foo 的调用编译得很好,因此看起来好像我能够修改 pointer-to-const 后面的对象。

为什么我能做到?

P.S. 这里有一个 live example at Coliru 可以说明我的观点。为简洁起见,我使用 int 而不是 SData.

这里有一个更简单的例子,看看你能不能算出来:

void f(int);          // takes a non-const int

int main() {
    std::set<int> s;  // elements are const ints
    for (auto n : s) {
        f(n);         // OK!?
    }
}

so I assume that the type of elem.first is const S*

没有。 map 中存储的密钥是​​ const,这意味着对于 std::map<S*, Data>,密钥将是 S* const(即 const 指针),而不是 const S* (即指向 const 的指针)。所以传给foo(S* ptr)就好了,const指针本身会被复制到参数

正如您提到的,

std::map<K, V>::value_typestd::pair<const K, V>。那么当 S* 代替 K 时,const K 是什么?可能会让您感到惊讶的答案不是 const S*。而是 S* const.