2016-08-22 68 views
-1

我有這樣的功能:不能使用map []運算符和const函數關鍵字嗎?

bool Table::FindCard(const int& i, const Card& card) const{ 
    std::vector<Card>::const_iterator iter = table[i].begin(); 
    for(; iter != table[i].end() ; ++iter){ 
    if(*iter == card){ 
     return true; 
    } 
    } 

    return false; 
} 

,其中卡是一個類,表是一類具有:

std::map<int, std::vector<Card> > table; 

如果我運行代碼,我得到這個錯誤:

Table.cc: In member function ‘bool Table::FindCard(const int&, const  Card&) const’: 
Table.cc:42:50: error: passing ‘const t_map {aka const std::map<int,  std::vector<Card> >}’ as ‘this’ argument discards qualifiers [-fpermissive] 
std::vector<Card>::const_iterator iter = table[i].begin(); 

但如果我刪除const關鍵字:

bool Table::FindCard(const int& i, const Card& card){ 
... 
} 

所有的作品。

原因是因爲operator []不是const?我知道一個const函數只能調用其他const函數。

感謝

+0

你試過'CBEGIN() '? –

+2

_「原因是因爲operator []不是const?」_是的,請看[這裏](http://en.cppreference.com/w/cpp/container/map/operator_at)。 –

回答

3

The reason is because operator[] isn't const? I know that a const function can call only other const function.

是; operator[]被指定創建一個新的默認構造的元素,如果該鍵不存在,並且這在const映射上是不明智的,因此它不被標記爲const

當然,你可以指定const版本拋出一個異常(如at一樣)或者 - 我不知道 - 叫terminate如果該鍵沒有找到,但可惜的標準不說。您將不得不使用at或(呃)find

0

對於std::map,operator[]將返回對與給定鍵相關的值的引用。如果該密鑰不存在,它將被插入。由於這明顯地改變了地圖,所以該函數不是const,並且不能針對const對象調用。

2

如果關鍵字還不存在,operator []會在地圖中插入一個元素。這不是一個常量操作。 使用map.at()來保存常量。

0

如前所述:operator[]no-cont的成員,您可以用at來代替。

我只是想補充以前的答案可編譯的代碼,以便給你一個視覺例子。

bool Table::FindCard(const int& i, const Card& card) const{ 
    std::vector<Card>::const_iterator iter = table.at(i).begin(); 
    for(; iter != table.at(i).end() ; ++iter){ 
    if(*iter == card){ 
     return true; 
    } 
    } 

    return false; 
} 
0

與所有C++庫決策一樣,存在一個哲學問題的根源。

vector,operator[]定義爲常量和非常量的情況。這是明智的,因爲對於長度爲N的矢量,operator[](0...N-1)總是具有含義,無論是否爲const。該元素將存在。

以此爲基線,地圖應該做什麼?確定是否存在任何下標(鍵)沒有絕對的標準。

隨着可變的operator[],選擇默認構建元素是合理的 - 在所有調用者引用它後,他希望它存在,並且我們可以使它存在。這是最令人驚訝的道路。

現在怎麼樣的不可改變的情況?元素可能存在也可能不存在,如果不存在,我們不能改變地圖,因爲這會違反const的精神。

我們也不應該拋出異常,因爲對於習慣於處理vector的人來說,這可能會讓人感到意外,因爲在這種情況下不會出現任何異常(或可能!)。然後我們會看到兩個類似的接口,它們的行爲非常不一樣。

答案是根本不提供mutable operator []。開發人員(如你)可能會驚訝地發現它不存在,但他們有機會查看文檔並意識到他們正在吠叫錯誤的樹。

如上所述,我們有at()(如果下標不存在,則拋出異常,如向量),我們有find()

與提升的幫助不大(很快,C++ 17),我們可以給自己一個效用函數:

#include <map> 
#include <string> 
#include <utility> 
#include <type_traits> 
#include <iostream> 
#include <boost/optional.hpp> 


template<class Map> 
auto maybe_get_impl(Map& map, typename Map::key_type const& key) 
{ 
    using reference_type = std::conditional_t< 
    std::is_const<std::remove_reference_t<Map>>::value, 
    typename Map::mapped_type const&, 
    typename Map::mapped_type&>; 
    boost::optional<reference_type> result; 
    auto ifind = map.find(key); 
    if (ifind != map.end()) 
    { 
     result = ifind->second; 
    } 
    return result; 
} 

template<class K, class V, class Comp, class A> 
auto maybe_get(std::map<K, V, Comp, A> const& map, K const& key) 
{ 
    return maybe_get_impl(map, key); 
} 

template<class K, class V, class Comp, class A> 
auto maybe_get(std::map<K, V, Comp, A>& map, K const& key) 
{ 
    return maybe_get_impl(map, key); 
} 

int main() 
{ 
    std::map<int, std::string> mymap; 
    mymap.emplace(1, "hello"); 
    mymap.emplace(2, "world"); 

    // note: non-const because we're taking a reference from a mutable map; 
    std::string part = std::string("goodbye, cruel world"); 

    std::cout << maybe_get(mymap, 1).value_or(part) << std::endl; 
    std::cout << maybe_get(mymap, 2).value_or(part) << std::endl; 
    std::cout << maybe_get(mymap, 0).value_or(part) << std::endl; 
} 

預期輸出:

hello 
world 
goodbye, cruel world