operator[] ambiguity resolution
-
30-06-2021 - |
Question
noob here. The following is a fragment from a class definition I came accross in a book example:
double& operator[](int i);
double operator[](int i) const;
My question is: why is this not ambiguous? When compiling the files of the project, the compiler doesn't give any error.
Also, in the following (imagine AnyClass contains a valarray<double>
object for example and I want to access it directly):
AnyClass test;
cout << test[2]
which version does the compiler use?
Solution
It's not ambiguous because the const
is part of the signature and can be used for overload resolution. So if you use operator[]
on a non-const object, it picks the overload without const
because that's the most specific one. And if you use it on a const object, it picks the overload with const
because that's the only one that applies.
OTHER TIPS
If called on a const
object, the const
version will be used, else the other one.
That's how the compiler resolves the ambiguity.
AnyClass test;
const AnyClass const_test;
std::cout << test[2]; // calls operator[](int)
std::cout << const_test[2]; // calls operator[](int) const
To understand this, you mostly simply need to realize that a const
on an argument is enough to disambiguate a call:
#include <iostream>
void foo(char* ptr)
{
std::cout << "mutable: " << ptr << std::endl;
}
void foo(const char* ptr)
{
std::cout << "const: " << ptr << std::endl;
}
int main()
{
const char* constHello = "hello";
char mutableHello[] = "hello";
foo(constHello);
foo(mutableHello);
}
This prints:
const: hello
mutable:hello
The compiler will choose the least restrictive overload it can. So if you use a char*
when there's a char*
overload, it's the one it will pick; but if there isn't any, the compiler will decide that casting it to a const char*
is a viable conversion (the converse is, obviously, not true).
Now, the very simple thing is that all methods pass a this
pointer as the first parameter of any function. This parameter is hidden for the sake of simplicity. The const
at the end of the method qualifies the this
argument. Since, as we've just seen, a const
on a pointer is enough to disambiguate overloads, this will effectively work.