为什么我可以将std :: map的键传递给期望非const的函数?

时间:2017-07-26 16:45:29

标签: c++ pointers stl const stdmap

根据std::map documentation,它将键值对存储在std::pair<const Key, Value>中,因此地图中的键是常量。

现在假设我有一个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的调用编译得很好,因此看起来很好看好像我能够修改指向const的后面的对象。

为什么我能够这样做?

P.S。这是live example at Coliru,说明了我的观点。为简洁起见,我使用int代替SData

3 个答案:

答案 0 :(得分:5)

  

所以我假设elem.first的类型是const S*

没有。存储在map中的密钥为const,这意味着对于std::map<S*, Data>,密钥将为S* const(即const指针),而不是const S* (即指向const的指针)。因此可以将其传递给foo(S* ptr)const指针本身将被复制到参数中。

答案 1 :(得分:3)

这是一个更简单的例子,看看你是否可以解决这个问题:

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!?
    }
}

答案 2 :(得分:1)

正如您所提到的,

std::map<K, V>::value_typestd::pair<const K, V>。那么当const K替换为S*时,K是什么?答案可能让你大吃一惊,不是const S*。而是S* const