C++ can';我是否将map[]运算符与const function关键字一起使用?
我得到了这个函数:C++ can';我是否将map[]运算符与const function关键字一起使用?,c++,constants,C++,Constants,我得到了这个函数: 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; } } retur
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;
}
#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;
}
一切顺利
原因是运算符[]不是常量?我知道一个常量函数只能调用其他常量函数
谢谢
原因是运算符[]不是常量?我知道一个常量函数只能调用其他常量函数
对,<如果键不存在,则指定code>运算符[]来创建新的默认构造元素,这在const
映射上是不合理的,因此它没有标记为const
当然,您可以指定
const
版本来抛出异常(正如at
所做的那样),或者-我不知道-如果找不到键,则调用终止
,但遗憾的是标准没有这样说。您必须使用at
或(ugh)查找
对于std::map
,操作符[]
将返回与给定键关联的值的引用。如果该键不存在,将插入该键。由于这明显改变了映射,因此此函数不是const
,不能针对const
对象调用。运算符[]将在键尚不存在的情况下向映射中插入元素。这不是一个常量操作。
使用map.at()保持常量。如前所述:
操作符[]
是无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;
}
bool表::FindCard(const int&i,const Card&Card)const{
std::vector::const_迭代器iter=table.at(i).begin();
对于(;iter!=表.at(i).end();++iter){
if(*iter==卡){
返回true;
}
}
返回false;
}
在这个问题的根源上有一个哲学问题,就像所有C++库的决定一样。
在向量
中,为常量和非常量情况定义了运算符[]
。这是合理的,因为对于长度为N的向量,运算符[](0…N-1)
将始终具有意义,无论是否为常量。元素将存在
以此为基准,地图应该做什么?没有绝对标准来确定是否存在任何下标(键)
使用可变操作符[]
,选择默认构造元素是合理的-在调用方引用它之后,他希望它存在,我们可以使它存在。这是一条最不令人惊讶的道路
那么不可变的情况呢?元素可能存在,也可能不存在,如果不存在,我们就不能对映射进行变异,因为这将违反const
的精神
我们也不应该抛出异常,因为对于习惯于处理vector
的人来说,这可能会让他们感到惊讶,因为在这里,不期望(或可能)出现异常。然后,我们将有两个外观相似、行为非常不同的接口
答案是根本不提供可变运算符[]。开发人员(像您一样)可能会惊讶地发现它并不存在,但他们有机会查看文档并意识到他们找错了方向
如前所述,我们有at()
(如果下标不存在,则抛出异常,如向量),我们有find()
在boost(很快,c++17)的帮助下,我们可以为自己提供一个实用函数:
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;
}
#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;
}
您是否尝试过cbegin()
?“原因是运算符[]不是常量?”是的,请参阅。
#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