Home > Enterprise >  Overloading operator[] only for members of a specific class
Overloading operator[] only for members of a specific class

Time:12-02

Edit: MyClass has been renamed to ReverseStringAccess for disambiguation.

I have a class which encapsulates a vector<string>. The class has an overloaded operator[] which can be used to read and modify the contents of the vector. This is how it looks (minimally):

class ReverseStringAccess {
    public:
        ReverseStringAccess() {}
        ReverseStringAccess(vector<string> _arr) arr(_arr) {}
        string& operator[](int index) {
            return arr[index];
        }
    private:
        vector<string> arr;
};

Now I need to be able to modify the contents of each string in the vector without directly accessing the vector (i.e. some sort of operator[][] which only works with vectors that are members of this class). The problem is that using ReverseStringAccess[][] will result in the default behavior of operator[] on strings. For example, this statement:

ReverseStringAccess[i][j]

would give the jth character of the ith string in the vector. But I want it to (for example) instead get the (length - j - 1)th character of the ith string in the vector, where length is the length of the ith string.

Is this possible? If yes, how?

CodePudding user response:

If you want my_object[i][k] to not invoke std::string::operator[] then don't return a std::string& from MyClass::operator[], but a proxy that implements the desired []:

class MyClass {
    public:
        MyClass() {}
        MyClass(vector<string> _arr) arr(_arr) {}

        struct MyProxy {
             std::string& str;
             char& operator[](size_t index) { /.../ }
             const char& operator[](size_t index) const { /.../ }
        };

        MyProxy operator[](int index) {
            return {arr[index]};
        }
    private:
        vector<string> arr;
};

CodePudding user response:

The question is how to achieve reverse indexing on members of vector<string> via [][].

This can be achieved via a wrapper class for std::string:

template<typename T>
class reverse_access {
    T& ref;
public:
     // create wrapper given reference to T
     reverse_access(T& ref_)
         : ref(ref_)
     {}

     // reverse access operator []
     auto operator[](size_t i) -> decltype(ref[0])
     { return ref[ ref.size() - 1 - i]; }
     auto operator[](size_t i) const -> decltype(ref[0])
     { return ref[ ref.size() - 1 - i]; }

      // allow implicit conversion to std::string reference if needed
     operator T&() { return ref; }
     operator const T&() const { return ref; }
};

// inside MyClass:
        reverse_access<string> operator[](int index) {
            return reverse_access<string>(arr[index]);
        }
        reverse_access<const string> operator[](int index) const {
            return reverse_access<const string>(arr[index]);
        }

And use return reverse_access<std::string>(arr[index]); in operator[] in MyClass. The added conversion operator allows implicit conversion to a reference to the original type.

Another option is to use a different operator that can take 2 arguments: myclass(vec_index,str_index):

        string::reference operator()(size_t vec_index, size_t str_index)
        {
            return arr[vec_index][ arr[vec_index].size() - str_index ];
        }
        string::const_reference operator()(size_t vec_index, size_t str_index) const
        {
            return arr[vec_index][ arr[vec_index].size() - str_index ];
        }

A third solution is to reverse all strings on construction of ReverseStringAccess:

ReverseStringAccess(vector<string> _arr) arr(_arr) 
{
   for (auto& str : arr)
       std::reverse(str.begin(), str.end());
}
  • Related