strange ambiguity in the derived class

Discussion in 'C++' started by vj, May 11, 2010.

  1. vj

    vj Guest

    Hello,

    Trying to compile the example at the end of this post, I am getting
    next errors:

    [packman@localhost test]$ g++ p.cpp
    p.cpp: In member function ‘void D::foo1()’:
    p.cpp:39: error: request for member ‘boo’ is ambiguous
    p.cpp:16: error: candidates are: const int& B::boo() const
    p.cpp:6: error: int& A::boo()
    p.cpp: In member function ‘void D::foo2() const’:
    p.cpp:41: error: request for member ‘boo’ is ambiguous
    p.cpp:16: error: candidates are: const int& B::boo() const
    p.cpp:6: error: int& A::boo()


    Can someone explain why the example doesn't compile?
    The signatures of A:boo() and B:boo() methods are different (one is
    const, other isn't).

    How to change the example, to make it compile?

    Thank in advance.




    And the example is here:

    #include <iostream>
    class A
    {
    public:
    virtual ~A(){}
    int& boo()
    { return vboo(); }
    private:
    virtual int& vboo() = 0;
    };

    class B
    {
    public:
    virtual ~B(){}
    const int& boo() const
    { return vboo(); }
    private:
    virtual const int& vboo() const = 0;
    };

    class C : public A, public B
    {
    public:
    C():p(5){}
    virtual ~C(){}
    private:
    virtual const int& vboo() const
    { return p; }
    virtual int& vboo()
    { return p; }
    int p;
    };

    class D
    {
    public:
    void foo1()
    { std::cout<<"D::foo1() ++c.boo()="<<++c.boo()<<std::endl; }
    void foo2() const
    { std::cout<<"D::foo1() c.boo()const="<<c.boo()<<std::endl; }
    private:
    C c;
    };

    int main()
    {
    D d;
    d.foo1();
    d.foo2();
    }
     
    vj, May 11, 2010
    #1
    1. Advertising

  2. On 11.05.2010 08:23, * vj:
    > Hello,
    >
    > Trying to compile the example at the end of this post, I am getting
    > next errors:
    >
    > [packman@localhost test]$ g++ p.cpp
    > p.cpp: In member function ‘void D::foo1()’:
    > p.cpp:39: error: request for member ‘boo’ is ambiguous
    > p.cpp:16: error: candidates are: const int& B::boo() const
    > p.cpp:6: error: int& A::boo()
    > p.cpp: In member function ‘void D::foo2() const’:
    > p.cpp:41: error: request for member ‘boo’ is ambiguous
    > p.cpp:16: error: candidates are: const int& B::boo() const
    > p.cpp:6: error: int& A::boo()
    >
    >
    > Can someone explain why the example doesn't compile?
    > The signatures of A:boo() and B:boo() methods are different (one is
    > const, other isn't).
    >
    > How to change the example, to make it compile?
    >
    > Thank in advance.
    >
    >
    >
    >
    > And the example is here:
    >
    > #include<iostream>
    > class A
    > {
    > public:
    > virtual ~A(){}
    > int& boo()
    > { return vboo(); }
    > private:
    > virtual int& vboo() = 0;
    > };
    >
    > class B
    > {
    > public:
    > virtual ~B(){}
    > const int& boo() const
    > { return vboo(); }
    > private:
    > virtual const int& vboo() const = 0;
    > };
    >
    > class C : public A, public B
    > {
    > public:
    > C():p(5){}
    > virtual ~C(){}
    > private:
    > virtual const int& vboo() const
    > { return p; }
    > virtual int& vboo()
    > { return p; }
    > int p;
    > };
    >
    > class D
    > {
    > public:
    > void foo1()
    > { std::cout<<"D::foo1() ++c.boo()="<<++c.boo()<<std::endl; }
    > void foo2() const
    > { std::cout<<"D::foo1() c.boo()const="<<c.boo()<<std::endl; }
    > private:
    > C c;
    > };
    >
    > int main()
    > {
    > D d;
    > d.foo1();
    > d.foo2();
    > }


    The error is apparently caused by the possible boo's coming from different
    classes, at some point before their signatures are considered.

    I think you can find the relevant sections of the standard yourself, but as a
    practical matter, put

    using A::boo;
    using B::boo;

    in the public section of your C class.

    Then (apparently) the compiler is happy to also consider the signatures, and
    discovers that one of them is a better match.


    Cheers & hth.,

    - Alf
    (blog at <url: http://alfps.wordpress.com>)
     
    Alf P. Steinbach, May 11, 2010
    #2
    1. Advertising

  3. vj

    Öö Tiib Guest

    On May 11, 9:23 am, vj <> wrote:
    > Hello,
    >
    > Trying to compile the example at the end of this post, I am getting
    > next errors:
    >
    > [packman@localhost test]$ g++ p.cpp
    > p.cpp: In member function ‘void D::foo1()’:
    > p.cpp:39: error: request for member ‘boo’ is ambiguous
    > p.cpp:16: error: candidates are: const int& B::boo() const
    > p.cpp:6: error:                 int& A::boo()
    > p.cpp: In member function ‘void D::foo2() const’:
    > p.cpp:41: error: request for member ‘boo’ is ambiguous
    > p.cpp:16: error: candidates are: const int& B::boo() const
    > p.cpp:6: error:                 int& A::boo()
    >
    > Can someone explain why the example doesn't compile?


    Because compiler does not understand what it is that you are
    attempting to call. Also it (in better English than i usually use)
    explains it in its error messages.

    > The signatures of A:boo() and B:boo() methods are different (one is
    > const, other isn't).


    So what? Your compiler anyway failed to resolve between them. Also
    newbie reading your code will likely be confused.

    > How to change the example, to make it compile?


    Either rename one of the functions from ambiquous candidate set
    (compiler very nicely explains what these are) or make it explicit
    what it is that you are calling by qualifying the called function.

    > Thank in advance.


    You are welcome.

    > And the example is here:
    >
    > #include <iostream>
    > class A
    > {
    >   public:
    >     virtual ~A(){}
    >     int& boo()
    >     { return vboo(); }
    >   private:
    >     virtual int& vboo() = 0;
    >
    > };
    >
    > class B
    > {
    >   public:
    >     virtual ~B(){}
    >     const int& boo() const
    >     { return vboo(); }
    >   private:
    >     virtual const int& vboo() const = 0;
    >
    > };
    >
    > class C : public A, public B
    > {
    >   public:
    >     C():p(5){}
    >     virtual ~C(){}
    >   private:
    >     virtual const int& vboo() const
    >     { return p; }
    >     virtual int& vboo()
    >     { return p; }
    >     int p;
    >
    > };
    >
    > class D
    > {
    >   public:
    >     void foo1()
    >     { std::cout<<"D::foo1()   ++c.boo()="<<++c.boo()<<std::endl; }
    >     void foo2() const
    >     { std::cout<<"D::foo1()   c.boo()const="<<c.boo()<<std::endl; }
    >   private:
    >     C c;
    >
    > };
    >
    > int main()
    > {
    >   D d;
    >   d.foo1();
    >   d.foo2();
    > }
     
    Öö Tiib, May 11, 2010
    #3
  4. Öö Tiib wrote:
    > On May 11, 9:23 am, vj <> wrote:
    >
    >> How to change the example, to make it compile?

    >
    > Either rename one of the functions from ambiquous candidate set
    > (compiler very nicely explains what these are) or make it explicit
    > what it is that you are calling by qualifying the called function.
    >


    But what if that is not an option? For example, instead of having
    methods named boo, A requires non-const operator[], and B requires const
    operator[]

    Alf's response in else-thread was right on the target :)
     
    Vladimir Jovic, May 11, 2010
    #4
  5. Alf P. Steinbach wrote:
    > On 11.05.2010 08:23, * vj:

    <snip>
    > The error is apparently caused by the possible boo's coming from
    > different classes, at some point before their signatures are considered.
    >
    > I think you can find the relevant sections of the standard yourself, but
    > as a practical matter, put
    >
    > using A::boo;
    > using B::boo;
    >
    > in the public section of your C class.
    >
    > Then (apparently) the compiler is happy to also consider the signatures,
    > and discovers that one of them is a better match.
    >


    Right. Thank you :)
     
    Vladimir Jovic, May 11, 2010
    #5
  6. vj

    Öö Tiib Guest

    On May 11, 12:26 pm, Vladimir Jovic <> wrote:
    > Öö Tiib wrote:
    > > On May 11, 9:23 am, vj <> wrote:

    >
    > >> How to change the example, to make it compile?

    >
    > > Either rename one of the functions from ambiquous candidate set
    > > (compiler very nicely explains what these are) or make it explicit
    > > what it is that you are calling by qualifying the called function.

    >
    > But what if that is not an option? For example, instead of having
    > methods named boo, A requires non-const operator[], and B requires const
    > operator[]


    Best practice rules i currently have to follow consider it a design
    bug when non-const operator[] is provided and const operator[] is not
    provided. It i think makes sense, too.

    > Alf's response in else-thread was right on the target :)


    Yes, i forgot to say that using declarations also help compiler to
    concentrate better (but do not help imaginary newbie reading the
    code). Alf posted recently (even more complex for me) problem where
    most ruling compilers did not find matching template despite using
    directive was used. There also using declaration was one way to
    resolve the problem.
     
    Öö Tiib, May 11, 2010
    #6
  7. Öö Tiib wrote:
    > On May 11, 12:26 pm, Vladimir Jovic <> wrote:
    >> Öö Tiib wrote:
    >>> On May 11, 9:23 am, vj <> wrote:
    >>>> How to change the example, to make it compile?
    >>> Either rename one of the functions from ambiquous candidate set
    >>> (compiler very nicely explains what these are) or make it explicit
    >>> what it is that you are calling by qualifying the called function.

    >> But what if that is not an option? For example, instead of having
    >> methods named boo, A requires non-const operator[], and B requires const
    >> operator[]

    >
    > Best practice rules i currently have to follow consider it a design
    > bug when non-const operator[] is provided and const operator[] is not
    > provided. It i think makes sense, too.


    I agree for a general case, but there are cases when the non-const
    operator[] is not needed, and using it is an error. What to do in that
    case? Throw an exception?
    Having the static analysis fail (compiling error) is better then doing a
    run-time check.

    For example, a device writes data to a buffer in memory. If this data
    should not be modified (only read), using non-const operator[] to access
    that memory is wrong, no?
    (I know I would need volatile in this example, but that is another story)
     
    Vladimir Jovic, May 11, 2010
    #7
  8. vj

    Öö Tiib Guest

    On May 11, 2:21 pm, Vladimir Jovic <> wrote:
    > Öö Tiib wrote:
    > > On May 11, 12:26 pm, Vladimir Jovic <> wrote:
    > >> Öö Tiib wrote:
    > >>> On May 11, 9:23 am, vj <> wrote:
    > >>>> How to change the example, to make it compile?
    > >>> Either rename one of the functions from ambiquous candidate set
    > >>> (compiler very nicely explains what these are) or make it explicit
    > >>> what it is that you are calling by qualifying the called function.
    > >> But what if that is not an option? For example, instead of having
    > >> methods named boo, A requires non-const operator[], and B requires const
    > >> operator[]

    >
    > > Best practice rules i currently have to follow consider it a design
    > > bug when non-const operator[] is provided and const operator[] is not
    > > provided. It i think makes sense, too.

    >
    > I agree for a general case, but there are cases when the non-const
    > operator[] is not needed, and using it is an error. What to do in that
    > case? Throw an exception?


    Only const is ok. The rules i follow say that sole non-const operator
    [] is error.

    > Having the static analysis fail (compiling error) is better then doing a
    > run-time check.


    Yes, most things that policies require are best to detect with static
    analysis tools if possible. It saves lot of time of reviewers, also
    new people pick up rules enforced by tools quicker and with less
    problems or hard feelings. Tools give the feedback fast and it really
    is not weakening the language at all when some obscure practices are
    forbidden.

    > For example, a device writes data to a buffer in memory. If this data
    > should not be modified (only read), using non-const operator[] to access
    > that memory is wrong, no?
    > (I know I would need volatile in this example, but that is another story)


    For ensuring that you use non-const operator [] ... define const
    reference to your container that enwraps the buffer and use it.
    Compilers optimize worthless additional indirections usually out. Yes,
    volatile is usually used when the memory location may be read/written
    by external hardware.
     
    Öö Tiib, May 11, 2010
    #8
  9. vj

    Öö Tiib Guest

    On May 11, 3:11 pm, Öö Tiib <> wrote:
    > On May 11, 2:21 pm, Vladimir Jovic <> wrote:
    >
    >
    >
    >
    >
    > > Öö Tiib wrote:
    > > > On May 11, 12:26 pm, Vladimir Jovic <> wrote:
    > > >> Öö Tiib wrote:
    > > >>> On May 11, 9:23 am, vj <> wrote:
    > > >>>> How to change the example, to make it compile?
    > > >>> Either rename one of the functions from ambiquous candidate set
    > > >>> (compiler very nicely explains what these are) or make it explicit
    > > >>> what it is that you are calling by qualifying the called function.
    > > >> But what if that is not an option? For example, instead of having
    > > >> methods named boo, A requires non-const operator[], and B requires const
    > > >> operator[]

    >
    > > > Best practice rules i currently have to follow consider it a design
    > > > bug when non-const operator[] is provided and const operator[] is not
    > > > provided. It i think makes sense, too.

    >
    > > I agree for a general case, but there are cases when the non-const
    > > operator[] is not needed, and using it is an error. What to do in that
    > > case? Throw an exception?

    >
    > Only const is ok. The rules i follow say that sole non-const operator
    > [] is error.
    >
    > > Having the static analysis fail (compiling error) is better then doing a
    > > run-time check.

    >
    > Yes, most things that policies require are best to detect with static
    > analysis tools if possible. It saves lot of time of reviewers, also
    > new people pick up rules enforced by tools quicker and with less
    > problems or hard feelings. Tools give the feedback fast and it really
    > is not weakening the language at all when some obscure practices are
    > forbidden.
    >
    > > For example, a device writes data to a buffer in memory. If this data
    > > should not be modified (only read), using non-const operator[] to access
    > > that memory is wrong, no?
    > > (I know I would need volatile in this example, but that is another story)

    >
    > For ensuring that you use non-const operator [] ... define const

    do not use ^^^
    > reference to your container that enwraps the buffer and use it.
    > Compilers optimize worthless additional indirections usually out. Yes,
    > volatile is usually used when the memory location may be read/written
    > by external hardware.- Hide quoted text -
     
    Öö Tiib, May 11, 2010
    #9
    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. =?ISO-8859-1?Q?Christian_Engstr=F6m?=

    base/derived ambiguity with gcc, but not with MSVC

    =?ISO-8859-1?Q?Christian_Engstr=F6m?=, Feb 11, 2004, in forum: C++
    Replies:
    2
    Views:
    364
    =?ISO-8859-1?Q?Christian_Engstr=F6m?=
    Feb 12, 2004
  2. Replies:
    4
    Views:
    658
    codigo
    May 4, 2005
  3. Replies:
    1
    Views:
    397
    myork
    May 23, 2007
  4. Replies:
    1
    Views:
    390
    Victor Bazarov
    May 23, 2007
  5. David
    Replies:
    3
    Views:
    406
    Grizlyk
    Jan 29, 2008
Loading...

Share This Page