稀疏向量的重载运算符 []

发布于 2024-08-03 19:49:49 字数 682 浏览 5 评论 0原文

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

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

在内部,它将由 std::map 表示(其中 V code> 是存储值的类型)。如果映射中不存在某个元素,我们将假设它等于模板参数中的值 Default

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

const 版本非常简单:检查索引是否在映射中,如果在,则返回其值,否则返回 Default

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

有什么办法可以解决这个问题吗?或者也许可以解决这个问题?

I'm trying to create a "sparse" vector class in C++, like so:

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

Internally, it will be represented by an std::map<int, V> (where V is the type of value stored). If an element is not present in the map, we will pretend that it is equal to the value Default from the template argument.

However, I'm having trouble overloading the subscript operator, []. I must overload the [] operator, because I'm passing objects from this class into a Boost function that expects [] to work correctly.

The const version is simple enough: check whether the index is in the map, return its value if so, or Default otherwise.

However, the non-const version requires me to return a reference, and that's where I run into trouble. If the value is only being read, I do not need (nor want) to add anything to the map; but if it's being written, I possibly need to put a new entry into the map. The problem is that the overloaded [] does not know whether a value is being read or written. It merely returns a reference.

Is there any way to solve this problem? Or perhaps to work around it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

提笔落墨 2024-08-10 19:49:49

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

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

There may be some very simple trick, but otherwise I think operator[] only has to return something which can be assigned from V (and converted to V), not necessarily a V&. So I think you need to return some object with an overloaded operator=(const V&), which creates the entry in your sparse container.

You will have to check what the Boost function does with its template parameter, though - a user-defined conversion to V affects what conversion chains are possible, for example by preventing there being any more user-defined conversions in the same chain.

淡水深流 2024-08-10 19:49:49

不要让非常量运算符&实现返回一个引用,但是一个代理对象。然后,您可以实现代理对象的赋值运算符,以区分对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
    }
};

Don't let the non-const operator& implementation return a reference, but a proxy object. You can then implement the assignment operator of the proxy object to distinguish read accesses to operator[] from write accesses.

Here's some code sketch to illustrate the idea. This approach is not pretty, but well - this is C++. C++ programmers don't waste time competing in beauty contests (they wouldn't stand a chance either). ;-)

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
    }
};
贵在坚持 2024-08-10 19:49:49

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

如果您想返回一个引用,这意味着该类的客户端可以将调用operator[]的结果存储在引用中,并在以后随时读取/写入它。如果您不返回引用,和/或不在每次寻址特定索引时插入元素,他们怎么能做到这一点? (另外,我感觉该标准需要一个适当的 STL 容器来提供 operator[] 以使该运算符返回一个引用,但我不确定这一点。)

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

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

当然,您总是可以说这不是现成的STL容器,并且operator[]不会返回用户可以存储的普通引用。也许那没关系。我只是想知道。

I wonder whether this design is sound.

If you want to return a reference, that means that clients of the class can store the result of calling operator[] in a reference, and read from/write to it at any later time. If you do not return a reference, and/or do not insert an element every time a specific index is addressed, how could they do this? (Also, I've got the feeling that the standard requires a proper STL container providing operator[] to have that operator return a reference, but I'm not sure of that.)

You might be able to circumvent that by giving your proxy also an operator V&() (which would create the entry and assign the default value), but I'm not sure this wouldn't just open another loop hole in some case I hadn't thought of yet.

std::map solves this problem by specifying that the non-const version of that operator always inserts an element (and not providing a const version at all).

Of course, you can always say this is not an off-the-shelf STL container, and operator[] does not return plain references users can store. And maybe that's OK. I just wonder.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文