与所有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
你试过'CBEGIN() '? –
_“原因是因为operator []不是const?”_是的,请看[这里](http://en.cppreference.com/w/cpp/container/map/operator_at)。 –