6

我正在尝试在 C++ 中创建一个“稀疏”矢量类,如下所示:

template<typename V, V Default>
class SparseVector {
    ...
}

在内部,它将由一个表示std::map<int, V>(其中V存储的值的类型)。如果地图中不存在元素,我们将假装它等于Default模板参数中的值。

但是,我在重载下标运算符时遇到了问题,[]. 我必须重载[]运算符,因为我将此类中的对象传递到期望[]正常工作的 Boost 函数中。

这个const版本很简单:检查索引是否在地图中,如果是则返回其值,Default否则。

但是,非常量版本要求我返回一个引用,这就是我遇到麻烦的地方。如果值只是被读取,我不需要(也不想)向地图添加任何东西;但如果它正在被写入,我可能需要在地图中添加一个新条目。问题是重载[]不知道一个值是被读取还是被写入。它只返回一个引用。

有没有办法解决这个问题?或者也许可以解决它?

4

3 回答 3

13

可能有一些非常简单的技巧,但除此之外,我认为operator[]只需要返回可以从 V 分配(并转换为 V)的东西,不一定是 V&。所以我认为你需要返回一些带有重载的对象operator=(const V&),这会在你的稀疏容器中创建条目。

但是,您必须检查 Boost 函数对其模板参数的作用 - 用户定义的到 V 的转换会影响可能的转换链,例如通过防止在同一链中存在更多用户定义的转换。

于 2009-09-06T16:41:39.917 回答
9

不要让非常量 operator& 实现返回一个引用,而是一个代理对象。然后,您可以实现代理对象的赋值运算符,以区分对 operator[] 的读取访问和写入访问。

这是一些代码草图来说明这个想法。这种方法并不漂亮,但很好——这是 C++。C++ 程序员不会浪费时间参加选美比赛(他们也没有机会)。;-)

template <typename V, V Default>
ProxyObject SparseVector::operator[]( int i ) {
   // At this point, we don't know whether operator[] was called, so we return
   // a proxy object and defer the decision until later
   return ProxyObject<V, Default>( this, i );
}

template <typename V, V Default>
class ProxyObject {
    ProxyObject( SparseVector<V, Default> *v, int idx );
    ProxyObject<V, Default> &operator=( const V &v ) {
      // If we get here, we know that operator[] was called to perform a write access,
      // so we can insert an item in the vector if needed
    }

    operator V() {
      // If we get here, we know that operator[] was called to perform a read access,
      // so we can simply return the existing object
    }
};
于 2009-09-06T17:43:57.497 回答
1

我想知道这个设计是否合理。

如果你想返回一个引用,这意味着该类的客户端可以将调用的结果存储operator[]在一个引用中,并在以后的任何时候读取/写入它。如果您不返回引用,和/或每次处理特定索引时不插入元素,他们怎么能这样做?(另外,我觉得该标准需要一个适当的 STL 容器operator[]来让该操作员返回一个引用,但我不确定。)

您也许可以通过给您的代理也提供一个operator V&()(这将创建条目并分配默认值)来规避这一点,但我不确定在某些情况下这是否会打开另一个我没有想到的漏洞然而。

std::map通过指定该运算符的非常量版本始终插入一个元素(并且根本不提供const版本)来解决此问题。

当然,你总是可以说这不是一个现成的 STL 容器,并且operator[]不返回用户可以存储的普通引用。也许没关系。我只是好奇。

于 2009-09-06T20:06:36.070 回答