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.