我不能使用带有const函数关键字的map []运算符吗?

时间:2016-08-22 17:35:23

标签: c++ 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;
}

其中Card是一个类,Table是一个类:

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函数。

由于

5 个答案:

答案 0 :(得分:3)

  

原因是因为operator []不是const?我知道const函数只能调用其他const函数。

是;如果密钥不存在,则operator[]被指定用于创建新的默认构造元素,并且这在const地图上是不合理的,因此它不是标记为const

当然,您可以指定const版本以引发例外(如at所做)或 - 我不知道 - 如果密钥不是&#39,请致电terminate发现,但唉,标准并没有这么说。您必须使用at或(ugh)find

答案 1 :(得分:2)

如果密钥尚不存在,

operator []会将一个元素插入到地图中。它不是const操作。 使用map.at()来保留constness。

答案 2 :(得分:0)

对于std::mapoperator[]将返回与给定密钥关联的值的引用。如果该密钥不存在,则将插入该密钥。由于这显然会更改地图,因此此功能不是const,也不能针对const对象进行调用。

答案 3 :(得分:0)

如上所述:operator[]no-cont成员,您可以使用at替换。

我只想在 compilable 代码中添加前面的答案,以便为您提供一个直观的示例。

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;
}

答案 4 :(得分:0)

正如所有c ++库决策一样,这里有一个哲学问题。

vector中,operator[]是针对const和非const情况定义的。这是明智的,因为对于长度为N的向量,{em}总是总是具有含义,无论是否为常数。该元素将存在。

以此为基线,地图应该做什么?没有绝对的标准来确定是否存在任何下标(密钥)。

使用mutable operator[](0...N-1),选择默认构造元素是合理的 - 在调用者引用它之后,他希望它存在,并且我们可以使它存在。这是最不让人惊讶的道路。

那么不可变的情况呢?该元素可能存在也可能不存在,如果不存在,我们就不能改变地图,因为这会违反operator[]的精神。

我们也不应该抛出异常,因为这对于习惯于处理const的人来说可能会令人惊讶,因为vector没有预期的异常(或者可能!)。然后,我们会有两个外观相似的界面。

答案是根本不提供可变的运算符[]。开发人员(像你一样)可能会惊讶地发现它不存在,但是他们有机会查看文档并意识到他们正在咆哮错误的树。

如前所述,我们有at()(如果下标不存在则抛出异常,如向量),我们有find()

在boost(很快,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