Pitfalls of C++’s subscript operator
What’s wrong with this C++ code?
#include <iostream> #include <string>
class Foo { public: Foo() { }
operator bool() { return true; }
std::string operator[](const std::string& s) { return s; } };
int main(void) { Foo foo; std::cout << foo["hello world!"] << std::endl; return 0; }
Answer:
Trying to compile the above code with gcc produces the following error:
In function `int main()':
ambiguous overload for `Foo &[const char[13]]'
candidates are: operator [](int, const char *) <builtin>
class string Foo::operator [](const string &)
Wha—? Where the heck did operator[](int, const char*) come from?
This little bit of goofiness is inherited from C. In C, the subscript operator is unintuitively commutative. That is, ptr[index] is exactly the same as index[ptr]!
In C, this is never a problem. Nobody writes code like index[ptr], and you can be blissfully ignorant that it’s allowed at all.
In C++, it can manifest itself where you don’t expect it, and this is what happens in the code above.
The compiler tries to parse the expression foo["hello world!"]. Foo doesn’t have an operator[](const char*) method (nor an operator[](const char[13]) one), so the compiler has two choices:
- It can coerce
"hello world!"to astd::stringand callFoo::operator[](const std::string&). - Since
Foohasoperator bool()defined, the compiler can castfooto abool. Now the expression involves abool(an integer type) and a string literal (a character array), and because the subscript operator is commutative for this situation, it is legal to use theboolas an index into"hello world!".
Each choice involves one cast, so the compiler considers both equally valid and can’t decide.
To fix this, we can add Foo::operator[](const char*) and make the const char* to std::string coercion explicit:
class Foo
{
public:
// ...
std::string operator[](const char* s)
{
return operator[](std::string(s));
}
}
1 Comment »
RSS feed for comments on this post.
hard core. i miss programming. i get further and further away from this crap each year.
— ben @ October 22, 2006, 6:13 pm (PT)