C++ - 基于赋值侧重载 [] 运算符

发布于 2024-12-04 08:24:39 字数 1008 浏览 0 评论 0 原文

我正在尝试用 c++ 编写一个动态数组模板,

我目前正在重载 [] 运算符,并且我想根据它们使用的赋值的哪一侧来实现不同的行为。

#include <iostream>
...

template <class T>
T dynamic_array<T>::operator[](int idx) {
    return this->array[idx];
}

template <class T>
T& dynamic_array<T>::operator[](int idx) {
    return this->array[idx];
}

using namespace std;
int main() {
    dynamic_array<int>* temp = new dynamic_array<int>();

    // Uses the T& type since we are explicitly 
    // trying to modify the stored object
    (*temp)[0] = 1;

    // Uses the T type since nothing in the array 
    // should be modified outside the array
    int& b = (*temp)[0]; 

    // For instance...
    b = 4;
    cout<<(*temp)[0]; // Should still be 1
    return 0;
}

由于显而易见的原因,当尝试像这样重载时,我会遇到编译器错误。

有没有正确的方法来做到这一点?

到目前为止我的搜索还没有成功。我所看到的重载 [] 运算符似乎都接受用户可以修改对象外部的存储项。

我已经实现了使用 (instance(int i), update(int i, T obj)) 的方法,但如果能够像常规数组一样使用此类,那就太好了。

I'm trying to write a dynamic array template in c++

I'm currently overloading the [] operators and I'd like to implement a different behavior based on which side of assignment they are used on.

#include <iostream>
...

template <class T>
T dynamic_array<T>::operator[](int idx) {
    return this->array[idx];
}

template <class T>
T& dynamic_array<T>::operator[](int idx) {
    return this->array[idx];
}

using namespace std;
int main() {
    dynamic_array<int>* temp = new dynamic_array<int>();

    // Uses the T& type since we are explicitly 
    // trying to modify the stored object
    (*temp)[0] = 1;

    // Uses the T type since nothing in the array 
    // should be modified outside the array
    int& b = (*temp)[0]; 

    // For instance...
    b = 4;
    cout<<(*temp)[0]; // Should still be 1
    return 0;
}

I get compiler errors when trying to overload like this for obvious reasons.

Is there a proper way to do this?

My search so far has not been successful. Anything I've seen with overloaded [] operators seems to accept that the user can modify the stored item outside of the object.

I've implemented methods to use (instance(int i), update(int i, T obj)) but it would be nice to be able to use this class like a regular array.

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

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

发布评论

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

评论(2

谜兔 2024-12-11 08:24:39

您不能仅重载返回类型。

提供常量和非常量访问器重载的标准方法是通过 this 的常量来区分:

T       & get()       { return x; }
const T & get() const { return x; }  // or T get() const;

对于常量版本,您可以返回常量引用或按值返回,具体取决于 >T 是 - const-reference 可能更普遍有用。

(当然,您可以编写 operator[](std::size_t i) 来代替 get()。我只是想保持简短。)


我不知道我不认为这能 100% 实现您的想法,但那是因为您的推理有误:int b = foo()永远成为对任何内容的引用,即使foo() 返回一个(常量或非常量)引用,因为 b 被声明为 int 类型,而不是 int& ;。实际上,当您说 int b = (*temp)[0]; 时,您实际上会调用非常量版本,但这实际上并不是问题。 (要获得常量版本,您必须说 int b = static_cast &>(*temp)[0];(*static_cast<; const dynamic_array *>(temp))[0] - 但何苦呢。)

You cannot overload only on return type.

The standard way to provide constant and non-constant accessor overloads is to differentiate by the constness of this:

T       & get()       { return x; }
const T & get() const { return x; }  // or T get() const;

For the constant version, you can return either a const-reference or by value, depending on what T is - const-reference is probably more universally useful.

(In place of get() you would write operator[](std::size_t i), of course. I just wanted to keep it short.)


I don't think this achieves 100% what you had in mind, but that's because you have an error in your reasoning: int b = foo() will never be a reference to anything, even if foo() returns a (const or non-const) reference, because b is declared to be of type int, not int&. Practically, you would actually call the non-const version when you say int b = (*temp)[0]; but that isn't actually a problem. (To get the constant version, you'd have to say int b = static_cast<const dynamic_array<int> &>(*temp)[0]; or (*static_cast<const dynamic_array<int> *>(temp))[0] - but why bother.)

像极了他 2024-12-11 08:24:39

Scott Meyers 在一本《Effective C++》书中谈到了这一点。基本上,技巧是从索引运算符(operator[]()operator[]() const)返回一个临时常量或非常量代理对象,然后重载该代理类的赋值和隐式转换运算符。像这样的事情:

template <class T>
class Array
{
  public:
    struct proxy {
      T& element;

      proxy(T& el) : element(el) {}

      operator const T& () const {
        return element; // For use on RHS of assignment
      }

      proxy& operator=(const T& rhs) {
        // For use on LHS of assignment
        // Add your logic here
      }
    };

    const proxy operator[](int i) const {
      return proxy(a[i]);
    }

    proxy operator[](int i) {
      return proxy(a[i]);
    }

  private:
     T* a;
};

我可能有一些细节错误,但想法是推迟决定元素位于分配的哪一侧,直到实际尝试分配给它。也就是说,您不知道在调用operator[]时会做什么,但当您尝试分配给后续元素引用时,您肯定会知道。

Scott Meyers talked about this in one of the Effective C++ books. Basically the trick was to return a temporary const- or non-const proxy object from the index operators (operator[]() and operator[]() const), then overload the assignment and implicit conversion operators for that proxy class. Something like this:

template <class T>
class Array
{
  public:
    struct proxy {
      T& element;

      proxy(T& el) : element(el) {}

      operator const T& () const {
        return element; // For use on RHS of assignment
      }

      proxy& operator=(const T& rhs) {
        // For use on LHS of assignment
        // Add your logic here
      }
    };

    const proxy operator[](int i) const {
      return proxy(a[i]);
    }

    proxy operator[](int i) {
      return proxy(a[i]);
    }

  private:
     T* a;
};

I may have some of the details wrong but the idea is to defer the decision of what side of the assignment the element is on until an actual attempt is made to assign to it. That is, you don't know what will be done at the time of the operator[] call, but you certainly do when you attempt to assign to the subsequent element reference.

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