简体   繁体   English

确定operator []用途的目的

[英]Determining Purpose of operator[] Usage

Let's say I have something like the following method in my container class: 假设我的容器类中有以下方法:

Datatype& operator[](const unsigned int Index) // I know this should use size_t instead.
{
    return *(BasePointer + Index); // Where BasePointer is the start of the array.
}

I'd like to implement some sort of bounds-checking for the MyInstance[Index] = Value usage so the container resizes automatically if the user tries to change a value outside its range. 我想对MyInstance[Index] = Value使用实现某种边界检查,以便当用户尝试更改其范围之外的值时,容器会自动调整大小。 However, I want something else to happen if the user tries to access a value outside the container's range, eg MyVariable = MyInstance[Index] . 但是,如果用户试图访问容器范围之外的值,我想要发生其他事情,例如MyVariable = MyInstance[Index] How can I detect how operator[] is being used? 如何检测operator[]的使用方式?

Sketch: 草图:

return a proxy object instead of the actual data entry. 返回代理对象而不是实际的数据条目。 The proxy object then defines operator = to handle the assignment case, and an implicit conversion operator for the reading-out case. 然后,代理对象定义operator =来处理赋值情况,并定义用于读出情况的隐式转换运算符。

template <typename T>
class AccessorProxy {
  friend class Container<T>;
public:
    AccessorProxy(Container<T>& data, unsigned index)
        : data(data), index(index) { }
    void operator =(T const& new_value) {
        // Expand array.
    }
    operator const T&() const {
        // Do bounds check.
        return *(data.inner_array + index);
    }
private:
    AccessorProxy(const AccessorProxy& rhs)
     : data(rhs.data), index(rhs.index) {}
    AccessorProxy& operator=(const AccessorProxy&);
    Container<T>& data;
    unsigned index;
};

template <typename T>
class ConstAccessorProxy {
  friend class Container<T>;
public:
    ConstAccessorProxy(const Container<T>& data, unsigned index)
        : data(data), index(index) { }
    operator const T&() const {
        // Do bounds check.
        return *(data.inner_array + index);
    }
private:
    ConstAccessorProxy(const ConstAccessorProxy& rhs)
     : data(rhs.data), index(rhs.index) {}
    ConstAccessorProxy& operator=(const ConstAccessorProxy&);
    const Container<T>& data;
    unsigned index;
};

AccessorProxy<Datatype> operator[](const unsigned int Index)
{
    return AccessorProxy<Datatype>(*this, Index);
}
ConstAccessorProxy<Datatype> operator[] const (const unsigned int Index)
{
    return ConstAccessorProxy<Datatype>(*this, Index);
}

The accessor classes will likely need to be be friends of the container class. 访问者类可能需要成为容器类的朋友。

Finding ways to avoid the code duplication is left as an exercise to the reader. 找到避免代码重复的方法留给读者练习。 :)

Use a dummy class type to represent expressions like MyInstance[Index] and delay figuring out what to do until that expression is used. 使用虚拟类类型来表示像MyInstance[Index]这样的表达式,并延迟确定在使用该表达式之前要执行的操作。

class MyContainer {
private:
    class IndexExpr {
    public:
        // Get data from container:
        operator const Datatype&() const;
        // Expand container if necessary, then store data:
        Datatype& operator=(const Datatype& value);

        // Treat MyInstance[i] = MyInstance[j]; as expected:
        Datatype& operator=(const IndexExpr& rhs)
        { return *this = static_cast<const Datatype&>(rhs); }
    private:
        IndexExpr(MyContainer& cont, unsigned int ind);
        MyContainer& container_;
        unsigned int index_;
        friend class MyContainer;
    };

public:
    IndexExpr operator[](unsigned int Index)
    { return IndexExpr(*this, Index); }

    // No IndexExpr needed when container is const:
    const Datatype& operator[](unsigned int Index) const;

    // ...
};

This is not a perfect answer to "how to detect", but, if the user is accessing the operator[] via a const instance, then throw an exception if the index is out of bounds. 这不是“如何检测”的完美答案,但是,如果用户通过const实例访问operator[] ,则在索引超出范围时抛出异常。 ie

Datatype const& operator[]() const { .. // don't modify here, throw exception

However, if the user is accessing the instance via a non const instance, then by all means expand if the index is out of bounds (and within your acceptable ranges) 但是,如果用户通过非const实例访问实例,那么如果索引超出范围(并且在可接受的范围内),请务必进行扩展

Datatype& operator[]() { .. // modify here

Basically, you are using the const attribute of the instance to determine what your semantics would be (as done in std::map - ie trying to call operator[] on a const instance of a map results in a compiler error - ie there is no const qualified operator[] for map, because the function is guaranteed to create a mapping if the key does not exist already.) 基本上,你使用实例的const属性来确定你的语义是什么(如在std::map所做的那样 - 即试图在std::map的const实例上调用operator[]导致编译器错误 - 即没有const限定的operator[]用于map,因为如果键已经存在,则保证函数创建映射。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM