[cfe-dev] Why doesn't this compile? clang implicit conversions & overload resolution

Matthieu Monrocq matthieu.monrocq at gmail.com
Wed Jan 18 12:40:11 PST 2012


Le 18 janvier 2012 04:16, Eli Friedman <eli.friedman at gmail.com> a écrit :

> On Tue, Jan 17, 2012 at 6:52 PM, Ryan Ericson <ryan.ericson at gmail.com>
> wrote:
> > Code:
> >
> > struct Base
> > {
> >    operator bool() const { return false; }
> > };
> >
> > struct foo
> > {
> >    foo(const char* c) {}
> > };
> >
> > struct Something : public Base
> > {
> >    void operator[](const foo& f) {}
> > };
> >
> > int main()
> > {
> >    Something d;
> >    d["32"]
> >    return 0;
> > }
> >
> > clang complains:
> > test4.cpp:22:6: error: use of overloaded operator '[]' is ambiguous
> > (with operand types 'Something' and 'const char [3]')
> >    d["32"]
> >    ~^~~~~
> > test4.cpp:16:10: note: candidate function
> >    void operator[](const foo& f) {}
> >         ^
> > test4.cpp:22:6: note: built-in candidate operator[](long, const char *)
> >    d["32"]
> >     ^
> > test4.cpp:22:6: note: built-in candidate operator[](long, const restrict
> char *)
> > test4.cpp:22:6: note: built-in candidate operator[](long, const volatile
> char *)
> > test4.cpp:22:6: note: built-in candidate operator[](long, const
> > volatile restrict char *)
> >
> > It looks like it is considering between:
> > 1. d["32"] -> which will call Something::operator[] after 1 user
> > defined conversion through constructor
> > 2. "32"[d] -> which will call built in operator[] of const char* after
> > 1 user defined conversion through operator double AND 1 standard
> > conversion (promotion?) from bool to long
>
> You aren't really stating it clearly, but yes, those are the relevant
> conversions.
>
> > My question is, why doesn't the compiler pick 1 when it seems to be a
> > better conversion sequence (cheaper according to the standard?).
>
> The part you're missing is that in (1) there's a user-defined
> conversion applied to the second argument, and in (2) there's a
> user-defined conversion applied to the first argument.  Per
> [over.match.best]p1, they're ambiguous because one operator has a
> better conversion for the first argument, and one has a better
> conversion for the second argument.
>
> BTW, C++11 provides an easy way to avoid this whole mess: you can mark
> the operator bool explicit.
>
> -Eli
>
>
In the absence of C++11, you might settle for the Safe Bool Idiom:

class Base {
  typedef void (Base::*SafeBool)();
  void cannot_be_compared();

public:

  operator SafeBool () const { return false ? &Base::cannot_be_compared :
0; }

};

-- Matthieu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20120118/906b59a7/attachment.html>


More information about the cfe-dev mailing list