我班上有2名操作员有点问题。
我的班级被宣布:
template <class keyType, class valueType>
class MyMap{
keyType keys[MAX];
valueType values[MAX];
int size;
}
我需要重新定义operator [],例如当我打电话:std::cout<<MyMap1["a"];
时。
keyType& operator[] (keyType key){}
工作正常。我也使用它来进行任务,这很好,例如:MyMap1["a"]="a1";
代码很完美。但是在我的operator[]
中我增加了size
参数,只有在我想要进行分配时它才有用。当我只做std::cout
时,我不想增加它。
所以也许我应该重新定义operator=
函数,但是当我不能写:
void operator=(valueType value){}
因为MyMap1["a"] = "a1"
的左侧成员是keyType
而不是MyMap
类型。
我该怎么办?
答案 0 :(得分:2)
问题本身并不是输出;这是你做什么的时候 钥匙不存在。我认为你指定是非常重要的 在走得更远之前。有很多可能性:
您可以执行std::map
所做的操作,并使用默认值插入它
值。这在很多情况下非常方便,但确实意味着
你不能在const地图上使用[]
。
您可以让操作符返回一个指针,返回null
如果对象不存在则指针。就个人而言,我不喜欢
这适用于operator[]
;这意味着你必须写东西
比如:ValueType* p = myMap[ key ]; if ( p != NULL ) ...
,哪个
[]
似乎并不自然。 (另一方面,它确实有效
以及find
或get
函数。)
你可以抛出一个异常(如果你的话,甚至可以使用一个断言)
提供contains
函数,并将其作为前提条件
[]
)。
您可以返回预定义的默认值。这有点像
与第一种解决方案相反;这意味着operator[]
永远不会改变地图,也没有必要
非常规版本。
最后(这似乎是你的目标):你
可以让operator[]
返回代理,以便取消
用作右值的myMap["a"]
与myMap["a"]
= something
之间。我的感觉是这个解决方案没有结婚
与C ++的工作方式有关,但它在其他语言中使用
(例如像Python)。
对于最后一个解决方案,您可以使用以下内容:
class MyMap
{
class Proxy
{
MyMap* myOwner;
KeyType myKey;
public:
Proxy( MyMap* owner, KeyType key )
: myOwner( owner )
, myKey( key )
{
}
Proxy const& operator=( ValueType value ) const
{
myOwner->insertOrUpdate( myKey, value );
return *this;
}
operator ValueType() const
{
if ( !myOwner->contains( myKey ) ) {
throw UnknownKeyException( myKey );
}
return myOwner->get( myKey );
}
};
public:
Proxy operator[]( KeyType key )
{
return Proxy( this, key );
}
};
答案 1 :(得分:1)
“但在我的算子[]中,我增加了尺寸参数”。
别。检查密钥是否存在,仅在插入新密钥时才递增size
。当你正在做std::cout
时,大概你只是在现有的键/值对上这样做。
[编辑]
鉴于评论,这是一个替代解决方案。在operator[]
中,返回MyMap<KeyType, ValueType>::proxy
。这包裹了MyMap&
和Key
。重载MyMap::proxy::operator=(ValueType)
以分配新值,并增加size
。重载MyMap::proxy::operator ValueType() const
以获取值。如果密钥不存在,则返回ValueType()
。
答案 2 :(得分:1)
当你写:
auto blah = map[key];
使用key
调用operator [],并返回一个值。
当你写:
map[key] = blah;
然后使用key
调用operator [key],并返回一个值,然后使用blah
参数调用operator =。
这意味着可能很难检测到您实际在何处阅读或写入地图。
然而,通常情况下,在READ情况下,案例可能会回落到被调用的value const& operator[] const
,而在写入过程中,它会是value& operator[]
而没有const 标记。因此,可能尝试通过const说明符重载运算符:提供2个运算符[] s,一个const,一个非const,并仅在后者中增加大小。
这很简单,但并不总能正常运行,因为您可能会在某个时候意外地将'operator []视为'read',但是编译器在此时无法确定const约束。我现在无法确切地说出何时以及如何以及是否有可能,但我想如果你对const不是很谨慎,你可以很容易地打出它。
如果你点击它,那么我所知道的唯一选择是在非const模式下为返回值提供一个包装器,并为const模式保持正常:
myMap::valueType const & operator[](key...) const
mymap::wrapper<myMap::valueType>& operator[](key...)
你的包装将会记得一个参考和到你的Map并woudl记住KEY,那个包装器将提供一个隐式转换-TO-valueType,它将提供一个分配运算符FROM-valueType-TO-wrappertype。隐式转换为值类型woudl执行read-from-map-from-given-key并且不会增加te计数器,而operator =(from-valuetype,to-wrappertype)将执行对映射的写入。
这肯定会奏效,但这种方法可能会过时。我不熟悉c'11的变化,所以现在可能有一些更好的选项 - 例如,移动&&
语义可能会在这里改变一些东西,即可能是重载
valueType&& operator[](key)
也是可能的----但我不知道。我只知道return-a-transparent-wrapper方法。
编辑:这是一个很好的(似乎完整的)适当的operator []重载示例,它支持读取和写入,并区分这两者:
stack: How to do some stuff with values assigned in subscript operator?
答案 3 :(得分:1)
如果要区分读写操作,解决方案是从operator []
返回代理对象。
答案 4 :(得分:0)
仅当size
中不存在key
时,您才会增加keys
,对吗?这就是std::map
的作用。因此,如果您只是打印地图的内容,您将读取现有密钥的值,因此size
将不会增加。