I have this code where Derived
is a subclass of Base
and I need to have a different version of the func
method assuming that proc
method is common and have a lot of statements.
Does concept and template programming allow such requirement?
The requirement is : having two distinct classes having the same code but each one have his own (specific) func method.
Could I achieve this without inheritance? Hereunder is the code.
// templateInheritance.cpp
#include <iostream>
template <typename T>
class Base{
public:
void func(){ // (1)
std::cout << "Base::func\n";
}
void proc()
{
// huge stuff goes here
func();
// huge stuff goes here
}
};
template <typename T>
class Derived: public Base<T>{
public:
void func(){ // (2)
std::cout << "Derived::func\n";
}
};
int main(){
std::cout << '\n';
Derived<int> derived;
derived.proc();
Base<int> base;
base.proc();
std::cout << '\n';
}
The expected output:
Derived::func
Base::func
My understanding is, that you want to have compile time polymorphism. That is really simple to implement and one common pattern is CRTP
For simplicity I split your Base
in a real base and a second Base which can then be used for creating instances while the first is really only the common base.
There is no need for concepts
nor any meta template programming.
Example:
#include <iostream>
template <typename T, typename MASTER>
class Base{
public:
void proc()
{
// huge stuff goes here
static_cast<MASTER*>(this)->func();
// huge stuff goes here
}
};
template <typename T>
class Base2: public Base< T, Base2<T>>
{
public:
void func(){ // (2)
std::cout << "Base::func\n";
}
};
template <typename T>
class Derived: public Base<T, Derived<T>>{
public:
void func(){ // (2)
std::cout << "Derived::func\n";
}
};
int main(){
std::cout << '\n';
Derived<int> derived;
derived.proc();
Base2<int> base;
base.proc();
std::cout << '\n';
}
If you already have a C++23 compliant compiler, you can simplify much more by using explicit this parameter
:
#include <iostream>
template <typename T>
class Base{
public:
void func(){ // (2)
std::cout << "Base::func\n";
}
void proc(this auto& self)
{
// huge stuff goes here
self.func();
// huge stuff goes here
}
};
template <typename T>
class Derived: public Base<T>{
public:
void func(){ // (2)
std::cout << "Derived::func\n";
}
};
int main(){
std::cout << '\n';
Derived<int> derived;
derived.proc();
Base<int> base;
base.proc();
std::cout << '\n';
}
see live with explicit this parameter
Or if you want to go with runtime polymorphism, you simply use virtual/override.
#include <iostream>
template <typename T>
class Base{
public:
virtual void func(){ // (2)
std::cout << "Base::func\n";
}
void proc()
{
// huge stuff goes here
func();
// huge stuff goes here
}
};
template <typename T>
class Derived: public Base<T>{
public:
void func() override { // (2)
std::cout << "Derived::func\n";
}
};
int main(){
std::cout << '\n';
Derived<int> derived;
derived.proc();
Base<int> base;
base.proc();
std::cout << '\n';
}
Runtime polymorphism takes another indirection by calling the function via a pointer. This takes a minimal amount of additional time. And, that is more important: A virtual function can never be a templated one. So if your design needs templated methods, you have to go with CRTP
or explicit this
and can add runtime polymorphism on top by e.g. using std::variant
& std::visit
.