{"id":62,"date":"2004-09-23T00:59:04","date_gmt":"2004-09-23T08:59:04","guid":{"rendered":"\/?p=62"},"modified":"2010-01-18T02:42:16","modified_gmt":"2010-01-18T10:42:16","slug":"pitfalls-of-cpp-subscript-operator","status":"publish","type":"post","link":"https:\/\/www.slimjimmy.com\/weblog\/archives\/2004\/09\/23\/pitfalls-of-cpp-subscript-operator\/","title":{"rendered":"Pitfalls of C++&#8217;s subscript operator"},"content":{"rendered":"<p>What&#8217;s wrong with this C++ code?<\/p>\n<pre class=\"example\">\r\n#include &lt;iostream&gt;\r\n#include &lt;string&gt;\r\n<br \/>\r\nclass Foo\r\n{\r\npublic:\r\n    Foo()\r\n    {\r\n    }\r\n<br \/>\r\n    operator bool()\r\n    {\r\n        return true;\r\n    }\r\n<br \/>\r\n    std::string operator[](const std::string&amp; s)\r\n    {\r\n        return s;\r\n    }\r\n};\r\n<br \/>\r\nint main(void)\r\n{\r\n    Foo foo;\r\n    std::cout &lt;&lt; foo[\"hello world!\"] &lt;&lt; std::endl;\r\n    return 0;\r\n}\r\n<\/pre>\n<p>Answer:<\/p>\n<p><!--more--><\/p>\n<p>Trying to compile the above code with gcc produces the following error:<\/p>\n<pre class=\"example\">\r\nIn function `int main()':\r\nambiguous overload for `Foo &amp;[const char[13]]'\r\ncandidates are: operator [](int, const char *) &lt;builtin&gt;\r\n                class string Foo::operator [](const string &amp;)\r\n<\/pre>\n<p>Wha&#8212;?  Where the heck did <code>operator[](int, const char*)<\/code> come from?<\/p>\n<p>This little bit of goofiness is inherited from C.  In C, <a href=\"http:\/\/c-faq.com\/aryptr\/joke.html\" class=\"unemphasized\">the subscript operator is unintuitively commutative<\/a>.  That is, <code>ptr[index]<\/code> is exactly the same as <code>index[ptr]<\/code>!<\/p>\n<p>In C, this is never a problem.  Nobody writes code like <code>index[ptr]<\/code>, and you can be blissfully ignorant that it&#8217;s allowed at all.<\/p>\n<p>In C++, it can manifest itself where you don&#8217;t expect it, and this is what happens in the code above.<\/p>\n<p>The compiler tries to parse the expression <code>foo[\"hello world!\"]<\/code>.  <code>Foo<\/code> doesn&#8217;t have an <code>operator[](const char*)<\/code> method (nor an <code>operator[](const char[13])<\/code> one), so the compiler has two choices:<\/p>\n<ul>\n<li>It can coerce <code>\"hello world!\"<\/code> to a <code>std::string<\/code> and call <code>Foo::operator[](const std::string&)<\/code>.<\/li>\n<li>Since <code>Foo<\/code> has <code>operator bool()<\/code> defined, the compiler can cast <code>foo<\/code> to a <code>bool<\/code>.  Now the expression involves a <code>bool<\/code> (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 the <code>bool<\/code> as an index into <code>\"hello world!\"<\/code>.<\/li>\n<\/ul>\n<p>Each choice involves one cast, so the compiler considers both equally valid and can&#8217;t decide.<\/p>\n<p>To fix this, we can add <code>Foo::operator[](const char*)<\/code> and make the <code>const char*<\/code> to <code>std::string<\/code> coercion explicit:<\/p>\n<pre class=\"example\">\r\nclass Foo\r\n{\r\npublic:\r\n    \/\/ ...\r\n<br \/>\r\n    std::string operator[](const char* s)\r\n    {\r\n        return operator[](std::string(s));\r\n    }\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>What&#8217;s wrong with this C++ code? #include &lt;iostream&gt; #include &lt;string&gt; class Foo { public: Foo() { } operator bool() { return true; } std::string operator[](const std::string&amp; s) { return s; } }; int main(void) { Foo foo; std::cout &lt;&lt; foo[&#8220;hello world!&#8221;] &lt;&lt; std::endl; return 0; } Answer:<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[23],"class_list":["post-62","post","type-post","status-publish","format-standard","hentry","category-programming","tag-cpp"],"_links":{"self":[{"href":"https:\/\/www.slimjimmy.com\/weblog\/wp-json\/wp\/v2\/posts\/62","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.slimjimmy.com\/weblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.slimjimmy.com\/weblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.slimjimmy.com\/weblog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.slimjimmy.com\/weblog\/wp-json\/wp\/v2\/comments?post=62"}],"version-history":[{"count":0,"href":"https:\/\/www.slimjimmy.com\/weblog\/wp-json\/wp\/v2\/posts\/62\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.slimjimmy.com\/weblog\/wp-json\/wp\/v2\/media?parent=62"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.slimjimmy.com\/weblog\/wp-json\/wp\/v2\/categories?post=62"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.slimjimmy.com\/weblog\/wp-json\/wp\/v2\/tags?post=62"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}