2017-07-26 53 views
3

根據std::mapdocumentation,它將鍵值對存儲在std::pair<const Key, Value>中,因此映射中的鍵是常量。爲什麼我可以將std :: map的鍵傳遞給期望非const的函數?

現在想象一下,我有一個std::map其中鍵是指向某些對象的指針。

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

讓我們也假設有一個允許S*參數的函數foo。現在

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

,問題是:當我遍歷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

+0

您正在製作該元素的副本;你可以做任何你想要的個人副本... –

+2

不要混淆const指針和不可變指針! –

+0

@KerrekSB啊,的確如此!我的工作日結束時,我的大腦讓我感到困惑:)謝謝! –

回答

5

,所以我假設的elem.first類型是const S*

號鍵存儲在mapconst,這意味着對於std::map<S*, Data>,密鑰將是S* const(即const指針),而不是const S*(即指向的指針)。因此可以將它傳遞給foo(S* ptr)const指針本身將被複制到參數中。

+0

你說得對,我把'const T *'與'T * const'混合在一起。這種事情有時會在工作日結束時發生:-)謝謝! –

+0

@VasiliyGalkin:一個注意:雖然'const X *'和'X const *'是一樣的東西,但是習慣於編寫'X const *'的習慣對於模板和typedefs的處理尤其有用,如果你想*可視化*。 – Nawaz

+0

@Nawaz nah,我會' t同意。但我不想' t想要另一個'const T *'vs'T const *'holywar;) –

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

啊,的確!我沒有足夠重視密鑰類型是'T * const'而不是'const T *'的事實。謝謝! –

+0

'auto n'生成一個副本,然後'f(int)'獲取一個副本。所以我不明白這個答案是通過使用副本來解釋的! – Nawaz

+0

@Nawaz:這與OP所面臨的情況基本相同:使用const set元素的副本可以調用一個採用非const值的函數。請注意,如果您有'f(int&)'和'for(auto&n:s)',則代碼將不起作用。我知道還有第二層次的混亂,但我認爲如果你能夠圍繞這個簡單的例子,你有足夠的差異信息來提出正確的問題。 –

1

std::map<K, V>::value_typestd::pair<const K, V>,正如您所提到的那樣。那麼當代替K時,const K是什麼?答案可能會讓你大吃一驚,不是const S*。而是S* const

相關問題