T::operator int () const ambiguous with T::operator Handle () const?

Discussion in 'C++' started by Tim Clacy, Apr 29, 2005.

  1. Tim Clacy

    Tim Clacy Guest

    Please illuminate; what operator of class 'Event' will get matched for these
    two cases [see Event outline later]:

    Event ev1;
    Event ev2;

    // Case 1
    //
    if (ev1)
    ;

    // Case 2
    //
    if (ev1 || ev2)
    ;

    I would have thought 'operator int ()' is the only obvious match, but my
    compiler generates errors:

    "ambiguous 3-way choice of conversion from 'struct Event' in Boolean
    context

    All I'm trying to do is wrap an OS event in a class that can be treated like
    a Boolean; can anyone explain what the ambiguity is and how it can be
    resolved (preferable without casts)?

    Best regards


    Tim





    typedef struct tagHandle { }* Handle;

    bool eventIsSignalled(Handle hEvent);

    struct Event
    {
    :
    bool IsSignalled() const { return eventIsSignalled(*this); }

    operator int () const { return IsSignalled(); }
    operator Handle () const { return handle; }

    private:
    Handle handle;
    };
     
    Tim Clacy, Apr 29, 2005
    #1
    1. Advertising

  2. Tim Clacy

    Shezan Baig Guest

    Tim Clacy wrote:
    > typedef struct tagHandle { }* Handle;
    >
    > bool eventIsSignalled(Handle hEvent);
    >
    > struct Event
    > {
    > :
    > bool IsSignalled() const { return eventIsSignalled(*this); }
    >
    > operator int () const { return IsSignalled(); }
    > operator Handle () const { return handle; }




    ints *and* pointers are convertible to boolean (with the same
    priority). So it is ambigious.



    >
    > private:
    > Handle handle;
    > };
     
    Shezan Baig, Apr 29, 2005
    #2
    1. Advertising

  3. Tim Clacy

    Guest

    Shezan Baig wrote:
    > Tim Clacy wrote:
    > > typedef struct tagHandle { }* Handle;


    try instead:
    struct Handle { SomeType* realHandle; };

    > > bool eventIsSignalled(Handle hEvent);
    > >
    > > struct Event
    > > {
    > > :
    > > bool IsSignalled() const { return eventIsSignalled(*this); }
    > >
    > > operator int () const { return IsSignalled(); }
    > > operator Handle () const { return handle; }

    >
    > ints *and* pointers are convertible to boolean (with the same
    > priority). So it is ambigious.
     
    , Apr 29, 2005
    #3
  4. Tim Clacy

    ben Guest


    > All I'm trying to do is wrap an OS event in a class that can be treated

    like
    > a Boolean; can anyone explain what the ambiguity is and how it can be
    > resolved (preferable without casts)?
    > ...
    > typedef struct tagHandle { }* Handle;
    >
    > bool eventIsSignalled(Handle hEvent);
    >
    > struct Event
    > {
    > :
    > bool IsSignalled() const { return eventIsSignalled(*this); }
    >
    > operator int () const { return IsSignalled(); }
    > operator Handle () const { return handle; }
    >
    > private:
    > Handle handle;
    > };
    >


    If Event::IsSignalled does fine, why use operator int?
    Event itself is not a handle, why provide Handle operator?

    To simplify:

    struct Event
    {
    private:
    Handle handle;

    public:
    Handle GetHandle() const
    {
    return handle;
    }

    operator int() const
    {
    return eventIsSignalled();
    }

    //...
    };
     
    ben, Apr 30, 2005
    #4
  5. Tim Clacy

    Tim Guest

    <> wrote in message
    news:...
    > Shezan Baig wrote:
    > > Tim Clacy wrote:
    > > > typedef struct tagHandle { }* Handle;

    >
    > try instead:
    > struct Handle { SomeType* realHandle; };


    Shezen,

    Hi. I can't try right now but how would that help?

    > ints *and* pointers are convertible to boolean (with the same
    > priority). So it is ambigious.


    Hmm, that means that no C++ class can be used in an 'if' statement if it has
    more than one operator that returns a POD type... doesn't it?
     
    Tim, Apr 30, 2005
    #5
  6. Tim Clacy

    Tim Guest

    "ben" <> wrote in message
    news:42733154$0$4656$...
    >
    > > All I'm trying to do is wrap an OS event in a class that can be treated

    > like
    > > a Boolean; can anyone explain what the ambiguity is and how it can be
    > > resolved (preferable without casts)?
    > > ...
    > > typedef struct tagHandle { }* Handle;
    > >
    > > bool eventIsSignalled(Handle hEvent);
    > >
    > > struct Event
    > > {
    > > :
    > > bool IsSignalled() const { return eventIsSignalled(*this); }
    > >
    > > operator int () const { return IsSignalled(); }
    > > operator Handle () const { return handle; }
    > >
    > > private:
    > > Handle handle;
    > > };
    > >

    >
    > If Event::IsSignalled does fine, why use operator int?
    > Event itself is not a handle, why provide Handle operator?
    >
    > To simplify:
    >
    > struct Event
    > {
    > private:
    > Handle handle;
    >
    > public:
    > Handle GetHandle() const
    > {
    > return handle;
    > }
    >
    > operator int() const
    > {
    > return eventIsSignalled();
    > }
    >
    > //...
    > };


    Ben,

    Hi. It looks like I'll have to run with your suggestion. 'operator int'; is
    convenient in 'if' and || expressions for exactly the same reason that you
    would prefer this:

    if (a || b || c)
    ;

    to this:

    if ((a != false) || (b != false) || (c != false))
    ;

    I'm a little disappointed that 'operator in' isn't a better match that
    'operator void*' in an 'if' expression. This is surely a case of 'C'
    crippling the power of C++ operator overloading isn't it?

    Regards


    Tim
     
    Tim, Apr 30, 2005
    #6
  7. Tim wrote:

    >> ints *and* pointers are convertible to boolean (with the same
    >> priority). So it is ambigious.

    > Hmm, that means that no C++ class can be used in an 'if' statement if it
    > has more than one operator that returns a POD type... doesn't it?


    Just define a conversion to bool for that class.

    --
    Salu2
     
    =?ISO-8859-15?Q?Juli=E1n?= Albo, Apr 30, 2005
    #7
  8. Tim Clacy

    Pete Becker Guest

    Re: T::eek:perator int () const ambiguous with T::eek:perator Handle ()const?

    Tim wrote:
    >
    > Hmm, that means that no C++ class can be used in an 'if' statement if it has
    > more than one operator that returns a POD type... doesn't it?
    >


    No. POD types aren't inherently convertible to bool. Some of them (in
    particular, builtin types) are.

    --

    Pete Becker
    Dinkumware, Ltd. (http://www.dinkumware.com)
     
    Pete Becker, Apr 30, 2005
    #8
  9. Tim Clacy

    Ian Guest

    Re: T::eek:perator int () const ambiguous with T::eek:perator Handle ()const?

    Julián Albo wrote:
    > Tim wrote:
    >
    >
    >>>ints *and* pointers are convertible to boolean (with the same
    >>>priority). So it is ambigious.

    >>
    >>Hmm, that means that no C++ class can be used in an 'if' statement if it
    >>has more than one operator that returns a POD type... doesn't it?

    >
    >
    > Just define a conversion to bool for that class.
    >

    And then live with all the bizarre run time errors such an operator will
    give you!

    Use a bool member like isOK(), the extra typing is worth it.

    Ian
     
    Ian, May 1, 2005
    #9
  10. Ian wrote:

    > Julián Albo wrote:
    >> Tim wrote:
    >>
    >>
    >>>>ints *and* pointers are convertible to boolean (with the same
    >>>>priority). So it is ambigious.
    >>>
    >>>Hmm, that means that no C++ class can be used in an 'if' statement if it
    >>>has more than one operator that returns a POD type... doesn't it?

    >> Just define a conversion to bool for that class.

    > And then live with all the bizarre run time errors such an operator will
    > give you!
    > Use a bool member like isOK(), the extra typing is worth it.


    I do. But the question was if that can be done.

    --
    Salu2
     
    =?ISO-8859-15?Q?Juli=E1n?= Albo, May 1, 2005
    #10
  11. Tim Clacy

    Tim Guest

    "Julián Albo" <> wrote in message
    news:...
    > Tim wrote:
    >
    > >> ints *and* pointers are convertible to boolean (with the same
    > >> priority). So it is ambigious.

    > > Hmm, that means that no C++ class can be used in an 'if' statement if it
    > > has more than one operator that returns a POD type... doesn't it?

    >
    > Just define a conversion to bool for that class.
    >
    > --
    > Salu2


    Julián,

    Hi. Are you saying that 'operator bool' would be matched in preference to
    'operator int' for an 'if' expression?
     
    Tim, May 2, 2005
    #11
  12. Tim wrote:

    > Hi. Are you saying that 'operator bool' would be matched in preference to
    > 'operator int' for an 'if' expression?


    Don't checked the standard but gcc accepts it:


    // boolconv.cpp

    #include <iostream>

    class Convertible {
    public:
    operator int () { return 0; }
    operator long () { return 0; }
    operator unsigned int () { return 0; }
    operator unsigned long () { return 0; }
    operator bool () { return true; }
    };

    int main ()
    {
    Convertible c;
    if (c)
    std::cout << "Hello, world" << std::endl;
    }

    $ g++ -Wall -pedantic -std=c++98 -o boolconv boolconv.cpp
    $ ./boolconv
    Hello, world


    But as Ian remarked, it's better to avoid that.

    --
    Salu2
     
    =?ISO-8859-15?Q?Juli=E1n?= Albo, May 2, 2005
    #12
  13. Tim Clacy

    Tim Clacy Guest

    Julián Albo wrote:
    > Tim wrote:
    >
    >> Hi. Are you saying that 'operator bool' would be matched in
    >> preference to 'operator int' for an 'if' expression?

    >
    > Don't checked the standard but gcc accepts it:
    >
    >
    > // boolconv.cpp
    >
    > #include <iostream>
    >
    > class Convertible {
    > public:
    > operator int () { return 0; }
    > operator long () { return 0; }
    > operator unsigned int () { return 0; }
    > operator unsigned long () { return 0; }
    > operator bool () { return true; }
    > };
    >
    > int main ()
    > {
    > Convertible c;
    > if (c)
    > std::cout << "Hello, world" << std::endl;
    > }
    >
    > $ g++ -Wall -pedantic -std=c++98 -o boolconv boolconv.cpp
    > $ ./boolconv
    > Hello, world
    >
    >
    > But as Ian remarked, it's better to avoid that.


    Julián,

    Cheers. Adding the 'operator bool' has fixed the issue; an 'Event' can used
    as Boolean and a Handle now. Why is it better to avoid 'operator bool'?
     
    Tim Clacy, May 3, 2005
    #13
  14. Tim Clacy wrote:
    >
    > Cheers. Adding the 'operator bool' has fixed the issue; an 'Event' can used
    > as Boolean and a Handle now. Why is it better to avoid 'operator bool'?


    The problem with all those conversion operators is that it enables
    the compiler to use them even in situations where you don't want them
    -> The compiler will use those operators to synthesize expressions which
    logically make no sense just to find a way to compile your code at all.

    Eg. if a class has an operator bool()

    class Test
    {
    operator bool() { ... }
    };

    then

    Test t;
    int i = t + 5;

    becomes a valid expression (because false -> 0, true -> 1)

    That is exactly why eg. the standard stream classes don't have an operator bool()

    --
    Karl Heinz Buchegger
     
    Karl Heinz Buchegger, May 3, 2005
    #14
  15. Tim Clacy

    Tim Clacy Guest

    Karl Heinz Buchegger wrote:
    > Tim Clacy wrote:
    >>
    >> Cheers. Adding the 'operator bool' has fixed the issue; an 'Event'
    >> can used
    >> as Boolean and a Handle now. Why is it better to avoid 'operator
    >> bool'?

    >
    > The problem with all those conversion operators is that it enables
    > the compiler to use them even in situations where you don't want them
    > -> The compiler will use those operators to synthesize expressions
    > which logically make no sense just to find a way to compile your code
    > at all.
    >
    > Eg. if a class has an operator bool()
    >
    > class Test
    > {
    > operator bool() { ... }
    > };
    >
    > then
    >
    > Test t;
    > int i = t + 5;
    >
    > becomes a valid expression (because false -> 0, true -> 1)
    >
    > That is exactly why eg. the standard stream classes don't have an
    > operator bool()


    Hmm, that's pretty disgusting... but couldn't you prevent this kind of
    anarchy by defining private operators (e.g. operator + (Event const &, int),
    operator + (Event const&, unsigned), etc.). In fact, couldn't you do all the
    dirty work in a template?

    template<typename T>
    class DisableStupidImplicitConversions
    {
    int operator + (int rhs);
    :
    };

    class Event : DisableStupidImplicitConversions<T>
    {
    :
    };

    Are there any other reasons for not defining an 'operator bool'? It seems
    like one of the most useful operators for bi-stable objects (like Event,
    Interrupt, Timer...).
     
    Tim Clacy, May 3, 2005
    #15
  16. Tim Clacy

    Kanenas Guest

    On Fri, 29 Apr 2005 18:45:08 +0200, "Tim Clacy"
    <> wrote:

    >Please illuminate; what operator of class 'Event' will get matched for these
    >two cases [see Event outline later]:
    >

    [...]
    >if (ev1 || ev2)
    > ;
    >
    >I would have thought 'operator int ()' is the only obvious match, but my
    >compiler generates errors:
    >
    > "ambiguous 3-way choice of conversion from 'struct Event' in Boolean
    >context
    >
    >All I'm trying to do is wrap an OS event in a class that can be treated like
    >a Boolean; can anyone explain what the ambiguity is and how it can be
    >resolved (preferable without casts)?
    >

    Shezan Baig summed up the ambiguity. As for what to do, I'd define
    'Event::eek:perator bool() const'.

    Kanenas
     
    Kanenas, May 30, 2005
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Timo Freiberger
    Replies:
    3
    Views:
    950
    Bob Hairgrove
    Oct 30, 2004
  2. Alex Vinokur
    Replies:
    4
    Views:
    3,051
    Peter Koch Larsen
    Nov 26, 2004
  3. Schnoffos
    Replies:
    2
    Views:
    1,218
    Martien Verbruggen
    Jun 27, 2003
  4. Hal Styli
    Replies:
    14
    Views:
    1,645
    Old Wolf
    Jan 20, 2004
  5. Replies:
    11
    Views:
    1,108
Loading...

Share This Page