2016-08-22 53 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