Suppose that all classes of a hierarchy implement a template member function g
. All classes share the same implementation of two other functions f1
and f2
that call this template:
struct A {
virtual void f1() {
g(5);
}
virtual void f2() {
g(5.5);
}
private:
template <typename T> void g(T) {std::cout << "In A" << std::endl;}
};
struct B: A {
// Can I get rid of this duplicate code?
virtual void f1() {
g(5);
}
virtual void f2() {
g(5.5);
}
private:
template <typename T> void g(T) {std::cout << "In B" << std::endl;}
};
struct C: A {
// Can I get rid of this duplicate code?
virtual void f1() {
g(5);
}
virtual void f2() {
g(5.5);
}
private:
template <typename T> void g(T) {std::cout << "In C" << std::endl;}
};
int main()
{
B b;
A &a = b;
a.f1();
return 0;
}
Since the implementations of f1
and f2
are identical in all the classes, how can I get rid of the duplicate code and still have the polymorphic call in main
work as expected (i.e produce the output "In B")?
Note that the implementations of f1
and f2
in A
, B
, and C
are not identical. Let's restrict it to f1
s. One calls a function named ::A::g<int>
, another one calls a function named ::B::g<int>
, and the third one calls a function named ::C::g<int>
. They are very far from identical.
The best you could do is have a CRTP-style base:
template <class Derived>
struct DelegateToG : public A
{
void f1() override
{
static_cast<Derived*>(this)->g(5);
}
void f2() override
{
static_cast<Derived*>(this)->g(5.5);
}
};
class B : public DelegateToG<B>
{
friend DelegateToG<B>;
private:
template <class T> void g(T) { /*...*/ }
};
class C : public DelegateToG<C>
{
friend DelegateToG<C>;
private:
template <class T> void g(T) { /*...*/ }
};
You can just factor out the class-specific things that the template function uses, such as (in your example) the class name:
#include <iostream>
using namespace std;
class A
{
private:
virtual auto classname() const -> char const* { return "A"; }
protected:
template <typename T> void g(T) {cout << "In " << classname() << endl;}
public:
virtual void f1() { g(5); }
virtual void f2() { g(5.5); }
};
class B
: public A
{
private:
auto classname() const -> char const* override { return "B"; }
};
class C
: public A
{
private:
auto classname() const -> char const* override { return "C"; }
};
auto main()
-> int
{ static_cast<A&&>( B() ).f1(); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With