strange ambiguity in the derived class

V

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();
}
 
A

Alf P. Steinbach

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>)
 
Ö

Öö Tiib

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.
 
V

Vladimir Jovic

Öö Tiib said:
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 :)
 
V

Vladimir Jovic

Alf said:
On 11.05.2010 08:23, * vj:
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 :)
 
Ö

Öö Tiib

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.
 
V

Vladimir Jovic

Öö Tiib said:
Öö Tiib said:
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)
 
Ö

Öö Tiib

Öö Tiib said:
Öö Tiib 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

Öö Tiib said:
Öö Tiib 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 -
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top