Why doesn't private inheritance resolve ambiguity for static functions ? (tested in MSVC)
Asked Answered
L

3

7

I'm wondering why a call to a static function is ambiguous, even when one of the two is obviously impossible to call as it is private. I was hoping I could use private / protected inheritance to help the compiler solve the ambiguity.

Is it specific to MSVC or is it somehow specified in the standard ?

struct A
{
    static int num() { return 0; }
};

struct B
{
    static int num() { return 1; }
};

struct C : public A, private B
{};

int main()
{
     C::num(); // Ambiguous access of num
}

The background is that I was trying a way of reusing an overloading behavior (the one in A) in many derived classes (C,D,E,F,G) by inheriting it, to adhere somehow to a rule of Don't Repeat Yourself.

Laborsaving answered 28/12, 2014 at 18:56 Comment(1)
access checking is done after overload resolutionWitenagemot
A
8

Yes it is specified in the C++ Standard, section §3.4 [basic.lookup]

The access rules (Clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded

Name lookup doesn't care about accessibility : it finds both A::num and B::num, so there is an ambiguity for the compiler.

You can explicitly call A::num with :

C::A::num();

If you explicitly try to call B::num, then your compiler will indeed emit an access error :

C::B::num(); // Error

You can also explicitly bring the base name into scope within the derived class, which will fix the ambiguity :

struct C : public A, private B
{
    using A::num;    
};
Alleviate answered 28/12, 2014 at 19:3 Comment(3)
I understand. So I can explicitly solve ambiguity in the derived, on a per-function basis, but there is no way to specify all members of one base class would take precedence over the other, which is what I was naively trying to achieve. The only way is by overloading 'vertically' if that makes any sense ?Laborsaving
Yes, that's correct. But generally speaking, you should first try to avoid name clashing (talking about non virtual members, of course), so the problem doesn't occur in the first place.Alleviate
The real life example is just slightly more complex : many derived have to overload A::num, but for the sake of verbosity and DRY they inherit the overload from another base class. I'll go with the using solution as it is the less verbose.Laborsaving
C
3

To help compiler you can do this

 struct C : public A, private B
 {
      using A::num;
 };
Cantwell answered 28/12, 2014 at 19:5 Comment(0)
H
2

Private members are intentionally considered for overload resolution.

Suppose you have

class C {
public:
  static void f(int);
  static void g();
private:
  static void f(long);
};

void C::g() {
  f(0L); // okay
}
void g() {
  f(0L); // error, does not silently call f(int)
}

Making only public members available during overload resolution causes highly surprising re-interpretations of code, where code that looks like it should work the exact same way would silently call different overloads.

Making such code an error was considered less troublesome than the alternative.

Hunks answered 28/12, 2014 at 19:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.