Reputation: 8126
I have some old code which allocates memory along the following lines:
class IntArrayAllocator
{
int* const m_array;
public:
IntArrayAllocator(int n) : m_array(new int[n]) {}
~IntArrayAllocator() { delete[] m_array; }
operator int*() const { return m_array; }
};
int main()
{
IntArrayAllocator allocator(10);
for(int i=0;i<10;++i) {
allocator[i] = i;
}
...
I'd like to start modernising this code by slotting in a wrapper instead of the raw pointer, like so:
class IntArray
{
int* const m_array;
public:
IntArray(int* array) : m_array(array) {}
int& operator[](int i) { return m_array[i]; }
int operator[](int i) const { return m_array[i]; }
};
class IntArrayAllocator
{
...
operator IntArray() const { return IntArray(m_array); } // replace previous operator int*
};
but then the user-defined conversion fails to work for the line
allocator[i] = i;
with the error no match for ‘operator[]’ (operand types are ‘IntArrayAllocator’ and ‘int’)
. I have to use, e.g.,
IntArray ia = allocator;
ia[i] = i;
instead.
This error confused the heck out of me as I thought I could just replace a user-defined conversion to a built-in type with a user-defined conversion to my own type (slotting in classes that mimic built-in types feels natural in object-oriented programming). The closest I came to understanding why is this answer: it doesn't make sense to allow user-defined conversion to lead to a call arbitrary member functions on other types. And it seems this applies to operators too, even though this initially felt like it ought to work in this case? (I'm aware that a lot of people think very deeply about the details of this kind of thing and there are very probably good reasons why this isn't allowed.)
Assuming I've hit a brick wall with user-defined conversion, what would be a good way to approach this problem?
Edit: I should clarify that this question is supposed to be a minimal example of an issue I experienced in trying to solve a larger problem. It wouldn't be suitable, for example, to solve the larger problem using a std::vector
, because, for example, I also need to be able to slice into an allocator, giving an int array object that refers to only part of the allocated memory. Also, the allocated memory won't always be allocated the same way: it may be from the heap, or the stack, returned from some 3rd party object, etc.
Upvotes: 0
Views: 63
Reputation: 473407
Remember that name[...]
is no different from name.operator[](...)
(when name
is not a pointer or array type). Type conversions don't get to happen on name
when you call member functions on it.
So what you want (to be able to inject an operator[]
into a type without adding such a member directly) is not possible. IntArrayAllocator
must have an operator[]
member function of its own. What it does is up to that, but it must have one.
Upvotes: 1