根据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
代替S
和Data
。
答案 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_type
是std::pair<const K, V>
。那么当const K
替换为S*
时,K
是什么?答案可能让你大吃一惊,不是const S*
。而是S* const
。