$ cat >test.cpp struct Edge { }; struct Node { void f (Edge&); }; struct AE : virtual Edge { }; struct AN : virtual Node { void f (AE&); using Node::f; }; struct BN : virtual Node { using Node::f; }; struct CN : virtual AN, virtual BN { }; void f () { AE e; CN n; n.f (e); } $ g++ --version g++ (GCC) 3.3.3 20031229 (prerelease) (Debian) $ g++ -c ./test.cpp test.cpp: In function `void f()': test.cpp:34: error: request for member `f' is ambiguous test.cpp:7: error: candidates are: void Node::f(Edge&) test.cpp:7: error: void Node::f(Edge&) test.cpp:17: error: void AN::f(AE&) $
I'm no expert in "using" things, but this really seems odd: ------------------ struct Node { void f (int); }; struct AN : virtual Node { using Node::f; }; struct BN : virtual Node { using Node::f; }; struct CN : virtual AN, virtual BN {}; void f () { CN n; n.f (1); } ------------------------------- With all gcc versions since 3.2 I get this: g/x> /home/bangerth/bin/gcc-3.4-pre/bin/c++ -c x.cc x.cc: In function `void f()': x.cc:17: error: request for member `f' is ambiguous x.cc:2: error: candidates are: void Node::f(int) x.cc:2: error: void Node::f(int) On the other hand, gcc2.95 and icc accept the code. I have no idea who's right, though. W.
Subject: Re: unexpected overload resolution After some more thinking I tend to believe that the two examples above and the code below should at least behave in a consistent manner (i.e. all fail or all compile): namespace A { void f (char); } namespace B { void f (char); } namespace C { void f (int); } void g () { using namespace A; using namespace B; using namespace C; int i; f (i); } GCC 3.3.3 compiles this example fine.
That's not a good example. The using directive for A::f and B::f create an ambiguity, but this only needs to be detected when you try to call one of the functions, i.e. during overload resolution, not when the using directive is parsed. However, you call f(int), and there is no ambiguity in this case. W.
Subject: Re: unexpected overload resolution > That's not a good example. The using directive for A::f and B::f create > an ambiguity, but this only needs to be detected when you try to call > one of the functions, i.e. during overload resolution, not when the > using directive is parsed. Agree. > However, you call f(int), and there is no ambiguity in this case. Doesn't the overload resolution happens when I call f(int) ? And according to what you just said it should be flagged as an error. And thus, I think, it's a very good example ;-) What I was trying to say is that when the same processes (overload resolution) happens in similar situations (ambiguilty in class inheritance vs ambiguilty in using directive) it would be nice if it had the same result (consistency).
There is no ambiguity in the call to f(int), because there is only one such function. That there might be an ambiguity for other argument types is irrelevant. There is also no ambiguity in my shortened example (and your original code): the base class is virtual, so there is exactly one copy and no ambiguity with what "this" pointer it has to be called. That doesn't mean, however, that a compiler is supposed to detect this special case of virtual base classes, though. W.
Confirmed with Wolfgang testcase: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13590#c1 There is only one Node base class because of the virtual inheritance, so there is only one Node::f function. There is no ambiguity. When the lookup is performed, it should be noted that the two using declarations *do* refer to the same declaration on the same base object. Boris, as Wolfgang explained, your other testcase is indeed non ambigous and correctly accepted by GCC since, at the point of call, there is only one and only one "best" overload.
This has been failing since at least 2000-12-31, this is a regression from 2.95.3.
I am not conviced this code is valid. [10.2] describes member name lookup in an MI lattice, and says that 'each declaration that was introduced by a using-declaration is considered to be from each subobject of C that is of the type containg the declaration descignated by the using declaration'. ... 'if the resulting set of declarations are not all from sbobjects of the same type ... there is an ambiguity'. Whilst those rules make sense for data members, they do not for function members. The set of overloaded functions can include some from a base, brought in by a using declaration, and some declared in the class containing the using declaration [7.3.3]/12 If those from the base were considered to actually be from the base, then we'd have a set from differnt types, so be ambiguous. Thus, I think we have to consider overloaded functions to be from the class containing the using declaration (and not the class being used). If that is the case, then the code is ill-formed, even though both using declarations refer to the same unambiguous base object. The original testcase had added an overload on one path through the graph, if we augment the case with an additional overload on the other path, it quite clearly must be ambiguous (because it would be without the using declarations). Wolfgang's reduced test case, with just using declarations it the other interesting example. If we treat this as ambiguous, then it appears that (in other useages), we could use using declarations to resolve inherited member ambiguities -- something expressly forbidden by [10.2] (footnote 96). So this argues that the reduced case should be well formed. But, now we have some strangeness. Whether a function using declaration's naming class is the class of the using declaration of the class of the used declaration depends on whether there are any additional overloads.
Nathan, can you raise this issue with the CWG? Maybe we can have some lights shed on this eventually. If you do that, we can suspend this bug until there is a clear position on the matter.
We're not even convinced yet that this is a bug, so I'm postponing this until 3.4.1.
Nathan -- is there any word from the committee on this issue?
Waiting for information from Nathan.
This is a bug in the standard, which the CWG has been working on fixing for quite a while: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#39
Suspending as the DR report is in review.
Postponed until GCC 3.4.2.
Just found a non-academic example when this really hurts: template<typename x> struct base { void f (); }; template <typename x> struct a : virtual base<x> { using base<x>::f; // which f void g () { f (); } }; template <typename x> struct b : virtual base<x> { using base<x>::f; // which f void g () { f (); } }; struct c : a<int>, b<int> {}; void f () { c c_; c_.f (); } Here I use using-declaration to hind the compiler which f() I am using since it does not depend on template parameter in any way. The result - call to c_.f () is ambiguous - IMO, is ridiculous.
Unsetting the target milestone as there is a stil opened DR about this.
As DR39 has been ruled a defect, this should be re-opened.
would the summary be clarified by changing "Non-existing ambiguity when inhering through virtuals two identical using declarations" to "Ambiguity due to two using declarations for same member of virtual base" ?
I think that non abiguous cases should be allowed. My basic inheritance structure is as follows: 01 class Base { 02 public: 03 virtual void foo() { cout << "Base" << endl; } 04 }; 05 class A : public Base { 06 public: 07 //using Base::foo; 08 //virtual void foo() { cout << "A" << endl; } 09 //virtual void foo() { Base::foo(); } 10 }; 11 class B : public Base { 12 public: 13 //virtual void foo() { cout << "B" << endl; } 14 }; 15 class AB : public A,B { 16 public: 17 //using Base::foo; 18 //using A::foo; 19 //using A::Base::foo; 20 //virtual void foo() { cout << "AB" << endl; } 21 }; 22 23 int main() { 24 //Base *p = new AB; 25 AB *p = new AB; 26 //p->foo(); 27 28 return 0; 29 } Currently only the following case is possible: 0.) uncomment line 09, 18, 26 which is the worst option I think The following cases should be allowed: 1.) uncomment line 24 // virtual and non virtual functions are unambiguous 2.) uncomment line 26 // it is clear to use HW::foo() -> both paths same properties 3.) uncomment line 17 // clear to use HW::foo() 4.) uncomment line 18 (perhaps together with line 07) // clear to use the inherited A::foo() which inherits from the HW::foo() 5.) change line 11 to "class B : private Base {" // only A::foo is accessible, B::foo not 6.) doing the the cases above without virtual
Since I'm not sure if any of the examples here are meant to be accepted (some definitely aren't) here's the example from the standard which should compile: struct A { int x; }; // S(x,A) = { { A::x }, { A }} struct B { float x; }; // S(x,B) = { { B::x }, { B }} struct C: public A, public B { }; // S(x,C) = { invalid, { A in C, B in C } } struct D: public virtual C { }; // S(x,D) = S(x,C) struct E: public virtual C { char x; }; // S(x,E) = { { E::x }, { E }} struct F: public D, public E { }; // S(x,F) = S(x,E) int main() { F f; f.x = 0; // OK, lookup finds E::x }
Not sure if Fabien is actively working on this..