Reputation: 8051
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")?
Upvotes: 8
Views: 187
Reputation: 145429
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(); }
Upvotes: 1
Reputation: 171177
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) { /*...*/ }
};
Upvotes: 3