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());
}