Search code examples
c++templatesc++14

"Overload" subscript-assignment operation in c++ 14


Issue:

I need to construct an array that stores one type of data but appears as another type for memory saving. Only the subscript operator ([]) is required.

Say, I have an array arr that appears as fp32 but stores int8 internally: When reading a value from arr by arr[i], overloading the subscript operator that returns by value just works. However when assigning a value with syntax like arr[i]=somevalue, as I cannot cast int8_t to float32_t with reference, I cannot modify the inside value.

What I tried:

Defining a separate method set(unsigned int index, float32_t value) would be a simple solution, but it will require modifying all other code interacting with the array, thus not favored.

I considered using a template datatype for internal storing, and overloading its operator=. However, in this case the returned type of the [] operator cannot be determined and I cannot proceed further.

Code

// dummy cast functions
int8_t complex_downcast(double x) { 
    return x;
}
double complex_upcast(int8_t x) {
    return x;
}

// current structure
template <typename T, unsigned int N> struct buffer {
    int8_t v[N];

    T get(int i) const {
        return complex_upcast(v[i]);
    }

    T operator[](int i) const {
        return get(i);
    }

    void set(int i, T v) {
        this->v[i] = complex_downcast(v);
    }
};

buffer<double, 1> buf;

buf.set(0, 2.1); // Sets 2.1, cast to int8 and stored
std::cout << buf[0] << std::endl; // (double) 2.0000000
// Want: replace buf.set(index, value) by buf[index] = value, where complex_downcast is required.

Solution

  • What you need to do is have the array class overload the operator[] to return a proxy object, and then have the proxy overload operator= for writing and operator T for reading. Then your proxy's operators can do whatever you want.

    Try something like this:

    template <typename T, unsigned int N> struct buffer {
        int8_t v[N];
    
        struct proxy {
            int8_t *elem;
            proxy& operator=(T value) {
                // whatever you need...
                *elem = static_cast<T>(value);
                return *this;
            }
            operator T() const {
                // whatever you need... 
                return static_cast<T>(*elem);
            }
        };
    
        proxy operator[](int i) {
            return proxy{ &v[i]; };
        }
    };
    

    Online Demo