How to correctly resolve parent member in class with virtual inheritance and overloading?

Viewed 28

Let's say I have a base class with 2 overloads for the same function; one in protected scope that is purely abstract, and one in public scope that calls the private one, like in the Parent class below:

#include <iostream>

enum class Type : bool { A = true, B = false};

class Foo { 
protected:
    int a;
public:
    Foo(int a): a(a) {};
    auto get() { return a; }
};

template<Type t>
class Bar : public Foo {
public:
    Bar(int a): Foo(a) {}
    Bar(Foo foo): Foo(foo) {}

    Bar<Type::B> makeB() {
        static_assert(t == Type::A);
        return Bar<Type::B>(a);
    }
};

class Parent {
public:
  virtual void run(Bar<Type::A> a) { return run(a.makeB()); }
protected:
  virtual void run(Bar<Type::B>) = 0;
};

Now I'd like to have a derived class which implements run(Bar<Type::B>), like so:

class Child  : public virtual Parent {
protected:
  virtual void run(Bar<Type::B> b) { 
      std::cout << "Parent::run()\n" << b.get() << "\n"; 
  }
};

Now, I would expect to be able to call Child::run(Bar<Type::A>) which would then call Child::run(Bar<Type::B>). However, the following does not compile:

int main() {
  auto f = Foo{1};
  Child c;
  c.run(Bar<Type::A>(f));
}

Result (Clang 13.0.1):

<source>:45:5: error: 'run' is a protected member of 'Child'
  c.run(Bar<Type::A>(f));
    ^
<source>:37:16: note: declared protected here
  virtual void run(Bar<Type::B> b) { 
               ^
1 error generated.

Godbolt: https://godbolt.org/z/Eb91nT9T1

Is there a way to do this properly? I want to have a pattern where one can only call Child::run(Bar<Type::A), and have the conversion to Type::B handled at the base class level. This way multiple derived classes can all implement a protected run(Bar<Type::B>), but the interface automatically handles conversions from Type::A.

0 Answers
Related