std::map::operator[]是一个设计得很磋却很好用的接口,看下面的例子:
#include <map>
#include <iostream>
using namespace std;
int main()
{
map<int, int> iiMap;
iiMap[1] = 2; ---------------------------(1)
iiMap[2]; --------------------------------(2)
cout << iiMap[1] << iiMap[2] << iiMap[3] << endl;
return 0;
}
operator[]的语义是说:我先查一下这个key,如果没有就先插入一个pair(key, Value()),然后把value的引用返回。
当(2)这样用时,它也会插入一对值(2,0),实际上你可能不希望这么做,可能你只是想看看key=2的值是多少或者存不存在?是的,它没有意识到何时需要,一定需要插入新值。显然,当[]作左值时需要,作右值时只要查一下就够了。
以自己的一个hash_table类为例,实现就省了,它有2个不磋的接口:
template<typename Key, typename Value, ...>
class hash_table
{
public:
Value* Get_Value(const Key& key);
Value* Set_Value(const Key& key, const Value& value);
...
};
为了实现更好的operator[],这个接口被设计成:
inline ValueWrapper operator[](const Key& key)
{
return ValueWrapper(key, Get_Value(key), this);
}
ValueWrapper是一个托管类,它是Value的一个包装:
class ValueWrapper
{
Key key;
Value* pValue;
hash_table_impl* mother;
public:
ValueWrapper(const Key& _key, Value* _pValue, hash_table_impl* _mother) :
key(_key), pValue(_pValue), mother(_mother)
{
}
...
};
它再重载operator=和operator Value,如下:
...
operator Value()
{
if (pValue)
{
return *pValue;
}
else
{
return Value();
}
}
ValueWrapper& operator=(const Value& value)
{
if (pValue)
{
*pValue = value;
}
else
{
mother->Set_Value(key, value);
}
return *this;
}
};
这样基本功能就完成了,它能感知=运算符,同时不失一般的在一些地方被隐式转化成Value。
如此还不够,像+= -= ++ --这些运算符也能代表着必须是左值,你如果一个一个重载,很麻烦,再写一个一般的包装类:
template<typename T>
class TypeWrapper
{
public:
explicit TypeWrapper(T* pReff = NULL) : m_pReff(pReff)
{
}
virtual ~TypeWrapper()
{
}
...
protected:
virtual T& get_lvalue()
{
return *m_pReff;
}
virtual T get_rvalue()
{
if (m_pReff)
{
return *m_pReff;
}
else
{
return T();
}
}
};
提供2个虚接口,他们分别是取左值和取右值,然后把所有赋值运算符++,--和operator T都重载好(使用宏减少重复性代码),如此再由它继承出前面的ValueWrapper,这样更简单,这样一个聪明的operator[]完成,它能在需要的时候insert一个新值,而其它时间都是在查看。