f



qualified member name lookup

Hello,

If I compile the following program with gcc, clang or comeau I get a error about ambiguity. Is this correct behavior?

struct a
{
    int foo;
};

struct a2 : virtual a
{};

struct b : a2
{};

struct c : a2
{};

struct d : b, c
{
    void f()
    {
        b::a2::foo; // OK for MSVC, ERROR for others
    }
};

(clang) error: ambiguous conversion from derived class 'd' to base class 'a2':
    struct d -> struct b -> struct a2
    struct d -> struct c -> struct a2

(gcc) error: 'a2' is an ambiguous base of 'd'

(comeau) error: base class "a2" is ambiguous

I explicitly specified that I want a2 in b. Why is there an ambiguity? I've looked in [basic.lookup.qual] and [class.member.lookup] and I haven't found anything relevant.

msvc doesn't show error about an ambiguity, but it also doesn't show errors in very simple cases (see below), so I don't take its results seriously.

struct a
{
    int x;
};

struct b : a
{};

struct c : a
{};

struct x : b, c
{
    void g()
    {
        a::x = 5; // OK for MSVC (and uses x->b->a), ERROR for others
    }
};

Thanks in advance.
0
vanyacpp (4)
8/24/2012 11:59:59 AM
comp.lang.c++ 49423 articles. 5 followers. Post Follow

3 Replies
315 Views

Similar Articles

[PageSpeed] 2

On Friday, August 24, 2012 1:59:59 PM UTC+2, vany...@gmail.com wrote:
> Hello,
> 
> 
> 
> If I compile the following program with gcc, clang or comeau 
> I get a error about ambiguity. Is this correct behavior?

IM(h)O, yes.

You inherited virtually from a, not a2. Therefore qualifying 
through a is not ambigious. Two instances of a2 exist (as 
you did not inherit virtually from it), which one (when 
qualified)? Only one instance of a exists( as you inherited
virtually from it).

This works fine:

struct a
{
  int foo;
};

struct a2 : virtual a
{};

struct b : a2
{};

struct c : a2
{};

struct d : b, c
{
    void f()
    {
      a::foo;
    }
};

Kind regards,

Werner
0
werasm (308)
9/5/2012 11:17:21 AM
On 2012-08-24 06:59, vanyacpp@gmail.com wrote:
> struct a
> {
>      int foo;
> };
>
> struct a2 : virtual a
> {};
>
> struct b : a2
> {};
>
> struct c : a2
> {};
>
> struct d : b, c
> {
>      void f()
>      {
>          b::a2::foo; // OK for MSVC, ERROR for others
>      }
> };
>
> (clang) error: ambiguous conversion from derived class 'd' to base class 'a2':
>      struct d -> struct b -> struct a2
>      struct d -> struct c -> struct a2
>
> (gcc) error: 'a2' is an ambiguous base of 'd'
>
> (comeau) error: base class "a2" is ambiguous

Effectively, the compiler treats that expression as

   static_cast<b::a2&>(*this).foo"

instead of

   static_cast<a2&>(static_cast<b&>(*this)).foo

which you seem to expect.

The expression is class member access (5.2.5) equivalent to 
(*this).b::a2::foo. According to the note in 5.2.5/2: "The program is 
also ill-formed if the naming class is an ambiguous base of the class 
type of the object expression; see 11.2." The naming class in this case 
- a2 - is an ambiguous base of the object expression, *this with type d. 
To be as clear as possible: the ambiguity doesn't occur in the name 
lookup, but in the conversion of *this.

You can remove the ambiguous conversion of *this in this case by simply 
referring to the member as "foo" or "a::foo" since a is a virtual base. 
If a was NOT virtual, you could use the names "b::foo" and "c::foo" 
since the conversions from d to b and d to c are unambiguous and the 
name "foo" would still be unique in the scope of b and c.

0
9/5/2012 7:55:10 PM
On Sep 5, 11:55=A0pm, Casey Carter
<casey_at_carter_dot_...@nospam.invalid> wrote:

> Effectively, the compiler treats that expression as
>
> =A0 =A0static_cast<b::a2&>(*this).foo"
>
> instead of
>
> =A0 =A0static_cast<a2&>(static_cast<b&>(*this)).foo
>
> which you seem to expect.
>
> To be as clear as possible: the ambiguity doesn't occur in the name
> lookup, but in the conversion of *this.

This is what I inferred from experiment with clang.

Thank you very much.
0
vanyacpp (4)
9/18/2012 7:05:40 AM
Reply: