I have a templated class TaskRunner that takes a polymorphic type Task and I want to create a container of shared pointers to them.
class Task {
virtual void run() = 0;
};
class LoudTask : Task {
void run() {
std::cout << "RUNNING!" << std::endl;
}
};
class QuietTask : Task {
void run() {
std::cout << "running!" << std::endl;
}
};
template<typename T> class TaskRunner {
public:
TaskRunner<T>() {
task = std::make_unique<T>();
}
private:
std::unique_ptr<T> task;
};
using Runner = std::shared_ptr<TaskRunner<Task>>;
However I get error: no matching member function for call to 'push_back' with:
std::vector<Runner> runners;
runners.push_back(std::make_shared<TaskRunner<QuietTask>>());
runners.push_back(std::make_shared<TaskRunner<LoudTask>>());
Due to:
note: candidate function not viable: no known conversion from 'shared_ptr<TaskRunner>' to 'const shared_ptr<TaskRunner>' for 1st argument
Implemented IgorTandetnik's suggestion, and it works for me:
#include <iostream>
#include <memory>
#include <vector>
class Task {
virtual void run() = 0;
};
class LoudTask : Task {
public:
void run() {
std::cout << "RUNNING!" << std::endl;
}
};
class QuietTask : Task {
public:
void run() {
std::cout << "running!" << std::endl;
}
};
class TaskRunnerBase
{
public:
virtual void run() =0;
};
template <class T>
class TaskRunner: public TaskRunnerBase {
public:
TaskRunner():
task(std::make_unique<T>()) {
}
void run() override
{
task->run();
}
private:
std::unique_ptr<T> task;
};
int main()
{
using Runner = std::shared_ptr<TaskRunnerBase>;
std::vector<Runner> runners;
runners.push_back(std::make_shared<TaskRunner<QuietTask>>());
runners.push_back(std::make_shared<TaskRunner<LoudTask>>());
runners[0]->run();
runners[1]->run();
}
Output:
running!
RUNNING!
Note however that TaskRunner doesn't need to be a template; as it is currently implemented above, it has a kind of double role: (1) task factory, and (2) container and runner of tasks.
paolo's answer separates this out nicely, there, the factory aspect is moved to the main function.
If TaskRunner is supposed to run tasks that inherit from Task only, you may consider de-templatizing it:
#include <iostream>
#include <memory>
#include <vector>
class Task {
public:
virtual void run() = 0;
};
class LoudTask : public Task {
public:
void run() override { std::cout << "RUNNING!" << std::endl; }
};
class QuietTask : public Task {
public:
void run() override { std::cout << "running!" << std::endl; }
};
class TaskRunner {
public:
explicit TaskRunner(std::unique_ptr<Task>&& task_)
: task(std::move(task_)) {}
void run() {
if (this->task) this->task->run();
}
private:
std::unique_ptr<Task> task;
};
int main() {
using Runner = std::shared_ptr<TaskRunner>;
std::vector<Runner> runners;
runners.push_back(
std::make_shared<TaskRunner>(std::make_unique<QuietTask>()));
runners.push_back(
std::make_shared<TaskRunner>(std::make_unique<LoudTask>()));
for (auto& runner : runners) runner->run();
}
This is another implementation that eliminates the need for another inheritance hierarchy and vtable since we already accomplished that with the Task hierarchy:
#include <iostream>
#include <vector>
class Task {
public:
virtual void run() = 0;
};
class LoudTask : public Task {
public:
void run() {
std::cout << "RUNNING!" << std::endl;
}
};
class QuietTask : public Task {
public:
void run() {
std::cout << "running!" << std::endl;
}
};
class TaskRunner {
public:
TaskRunner(std::unique_ptr<LoudTask> task) : m_task{ std::unique_ptr<Task>(task.release()) } {}
TaskRunner(std::unique_ptr<QuietTask> task) : m_task{ std::unique_ptr<Task>(task.release()) } {}
void run()
{
m_task->run();
}
private:
std::unique_ptr<Task> m_task;
};
using Runner = std::shared_ptr<TaskRunner>;
int main()
{
std::vector<Runner> runners;
runners.push_back(std::make_shared<TaskRunner>(std::make_unique<QuietTask>()));
runners.push_back(std::make_shared<TaskRunner>(std::make_unique<LoudTask>()));
runners[0]->run();
runners[1]->run();
}
Related
I am trying to organize public member function in groups and sub groups. But I would like these functions to have access to all public and private members of the class. Here is a code that does the job, but it is ugly. I am looking for more elegant way of doing the same thing.
#include "iostream"
class tClass
{
public:
tClass()
{
this->Grp1.SubGrp1.me = this;
this->Grp1.SubGrp2.me = this;
this->Grp1.SubGrp3.me = this;
};
~tClass() {};
struct Grp1
{
struct SubGrp1
{
tClass* me;
void Fun1(void) { me->Group1_SubGroup1_Function1(); };
void Fun2(void) { me->Group1_SubGroup1_Function2(); };
void Fun3(void) { me->Group1_SubGroup1_Function3(); };
}SubGrp1;
struct SubGrp2
{
tClass* me;
void Fun1(void) { me->Group1_SubGroup2_Function1(); };
void Fun2(void) { me->Group1_SubGroup2_Function2(); };
}SubGrp2;
struct SubGrp3
{
tClass* me;
void Fun1(void) { me->Group1_SubGroup3_Function1(); };
}SubGrp3;
}Grp1;
private:
void Group1_SubGroup1_Function1(void) { std::cout << "Group1_SubGroup1_Function1\n"; };
void Group1_SubGroup1_Function2(void) { std::cout << "Group1_SubGroup1_Function2\n"; };
void Group1_SubGroup1_Function3(void) { std::cout << "Group1_SubGroup1_Function3\n"; };
void Group1_SubGroup2_Function1(void) { std::cout << "Group1_SubGroup2_Function1\n"; };
void Group1_SubGroup2_Function2(void) { std::cout << "Group1_SubGroup2_Function2\n"; };
void Group1_SubGroup3_Function1(void) { std::cout << "Group1_SubGroup3_Function1\n"; };
};
int main()
{
tClass aClass;
aClass.Grp1.SubGrp1.Fun1();
aClass.Grp1.SubGrp1.Fun2();
aClass.Grp1.SubGrp1.Fun3();
aClass.Grp1.SubGrp2.Fun1();
aClass.Grp1.SubGrp2.Fun2();
aClass.Grp1.SubGrp3.Fun1();
}
This is an IDE feature, not a C++ one.
For example visual studio allows for this (might not work in other environments). This allows you to group without impacting source code.
Bonus you can collapse groups to one line and expand them later.
#pragma region my_group_1
#pragma region sub_group_1
void func1();
#pragma endregion
#pragma region sub_group_2
void func2();
#pragma endregion
#pragma endregion
Mnd, this is how would organize your code example :
#include <iostream>
#include <string>
//------------------------------------------------------------------------------
// a base class to get all the constructors/destructors setup
// for an abstract base class ("interface")
struct interface_t
{
public:
interface_t(const interface_t&) = delete;
interface_t& operator=(const interface_t&) = delete;
interface_t(interface_t&&) = delete;
protected:
interface_t() = default;
virtual ~interface_t() = default;
};
//------------------------------------------------------------------------------
// now setup interfaces for all your groups
class group1_subgroup1_itf :
public interface_t
{
public:
virtual void fun1() = 0;
virtual void fun2() = 0;
};
class group1_subgroup2_itf :
public interface_t
{
public:
virtual void fun3() = 0;
virtual void fun4() = 0;
};
class group1_itf :
public interface_t
{
public:
virtual group1_subgroup1_itf& sub1() = 0;
virtual group1_subgroup2_itf& sub2() = 0;
};
class t_class_itf :
public interface_t
{
public:
virtual group1_itf& group1() = 0;
};
//------------------------------------------------------------------------------
// Then put your implementation all in one class, just like normal.
// let this class implement all the interfaces (groupings)
//
namespace impl
{
class t_class :
public t_class_itf,
public group1_itf,
public group1_subgroup1_itf,
public group1_subgroup2_itf
{
public:
explicit t_class(const std::string name) :
m_name{ name }
{
};
virtual ~t_class() override = default;
// todo other constructors
// implementation of navigation functions, they all end up in the same implementation.
virtual group1_itf& group1() override {return dynamic_cast<group1_itf&>(*this); }
virtual group1_subgroup1_itf& sub1() override { return dynamic_cast<group1_subgroup1_itf&>(*this); }
virtual group1_subgroup2_itf& sub2() override { return dynamic_cast<group1_subgroup2_itf&>(*this); }
// implementations
virtual void fun1() override { std::cout << m_name << "::fun1" << std::endl; }
virtual void fun2() override { std::cout << m_name << "::fun2" << std::endl; }
virtual void fun3() override { std::cout << m_name << "::fun3" << std::endl; }
virtual void fun4() override { std::cout << m_name << "::fun4" << std::endl; }
private:
std::string m_name;
};
} /* namespace impl */
//------------------------------------------------------------------------------
// client facing class
// used for "navigation" only
//
class t_class :
public t_class_itf
{
public:
explicit t_class(const std::string& name) :
m_impl{ name }
{
};
virtual group1_itf& group1() override { return dynamic_cast<group1_itf&>(m_impl); }
private:
impl::t_class m_impl;
};
//------------------------------------------------------------------------------
// and then its use.
int main()
{
t_class t{"t_class"};
t.group1().sub1().fun1();
t.group1().sub2().fun4();
return 0;
}
Thanks to all commends I got ideas how to decrease the complexity.
Here is simple solution and better example that exercises public/private access rights.
Memory Overhead: Extra pointer in each subgroup.
Code Overhead: Dynamic Initialization of all subgroup pointers.
#include "iostream"
class tClass
{
public:
tClass()
{
this->Grp1.SubGrp1.me = this;
this->Grp1.SubGrp2.me = this;
this->Grp1.SubGrp3.me = this;
};
~tClass() {};
struct Grp1
{
struct SubGrp1
{
tClass* me;
void Fun1(void) { me->aVar = 0x0101; me->mCount++; std::cout << "Group1_SubGroup1_Function1 Count=" << me->mCount << "\n"; };
void Fun2(void) { me->aVar = 0x0102; me->mCount++; std::cout << "Group1_SubGroup1_Function2 Count=" << me->mCount << "\n"; };
void Fun3(void) { me->aVar = 0x0103; me->mCount++; std::cout << "Group1_SubGroup1_Function3 Count=" << me->mCount << "\n"; };
}SubGrp1;
struct SubGrp2
{
tClass* me;
void Fun1(void) { me->aVar = 0x0201; me->mCount++; std::cout << "Group1_SubGroup2_Function1 Count=" << me->mCount << "\n"; };
void Fun2(void) { me->aVar = 0x0201; me->mCount++; std::cout << "Group1_SubGroup2_Function2 Count=" << me->mCount << "\n"; };
}SubGrp2;
struct SubGrp3
{
tClass* me;
void Fun1(void) { me->aVar = 0x0301; me->mCount++; std::cout << "Group1_SubGroup3_Function1 Count=" << me->mCount << "\n"; };
}SubGrp3;
}Grp1;
unsigned int aVar = 0x0000;
private:
int mCount = 0;
};
int main()
{
tClass aClass;
aClass.Grp1.SubGrp1.Fun1();
aClass.Grp1.SubGrp1.Fun2();
aClass.Grp1.SubGrp1.Fun3();
aClass.Grp1.SubGrp2.Fun1();
aClass.Grp1.SubGrp2.Fun2();
aClass.Grp1.SubGrp3.Fun1();
}
if i use the virtual function (*1) in the base class - the following code works as i inspected (print a_tmp and print b_tmp) but not if i use override function's (*2) (2x "print base" will be shown). What is the correct way to call the functions (async) in case of override functions?
#include <iostream>
#include <future>
#include <vector>
class base
{
public:
virtual void print() = 0; // *1
// void print() { std::cout << "print base" << std::endl; }; // *2
};
class a_tmp : public base
{
public:
void print() { std::cout << "print a_tmp" << std::endl; };
};
class b_tmp : public base
{
public:
void print() { std::cout << "print b_tmp" << std::endl; }
};
std::vector<std::future<void>> future_result;
int main()
{
a_tmp a_1_tmp;
b_tmp b_2_tmp;
base* ab_array[] = { &a_1_tmp,&b_2_tmp };
for (auto ptr : ab_array)
{
future_result.push_back(async(std::launch::async, &base::print ,ptr));
}
for (auto& e : future_result) {
e.get();
}
}
I would like to have a child class Handler that handles multiple callbacks and transfers data from one class to another. However, the base classes B1 and B2can have different implementations for its members.
Below a way to implement the behavior I want. I think there should be a better way but cannot figure it out.
// Example program
#include <iostream>
#include <string>
template <class T>
class IBase
{
public:
IBase()
{
object = new T(*this);
};
~IBase()
{
delete object;
}
virtual void ValidateCallback()
{
};
void RxCallback()
{
object->RxCallback();
};
void Send()
{
object->Send();
};
T* object;
};
class C1
{
public:
virtual void RxCompleteCallback() = 0;
void RxParse()
{
std::cout << "Parse C1" << std::endl;
RxCompleteCallback();
};
};
class C2
{
public:
virtual void RxCompleteCallback() = 0;
void RxParse()
{
std::cout << "Parse C2" << std::endl;
RxCompleteCallback();
};
};
class B1 : public C1
{
public:
B1(IBase<B1> &handler )
{
ihandler = &handler;
};
void DoSomething()
{
std::cout << "DoSomething B1" << std::endl;
ihandler->ValidateCallback();
};
void RxCompleteCallback() override
{
std::cout << "DoSomething other than B2" << std::endl;
std::cout << "RxCompleteCallback" << std::endl;
};
void RxCallback()
{
RxParse();
};
void Send()
{
DoSomething();
};
IBase<B1> * ihandler;
};
class B2 : public C2
{
public:
B2(IBase<B2> &handler )
{
ihandler = &handler;
};
void DoSomething()
{
std::cout << "DoSomething B2" << std::endl;
ihandler->ValidateCallback();
};
void RxCompleteCallback() override
{
std::cout << "DoSomething other than B1" << std::endl;
std::cout << "RxCompleteCallback" << std::endl;
};
void RxCallback()
{
RxParse();
};
void Send()
{
DoSomething();
};
IBase<B2> * ihandler;
};
class Validate
{
public:
void CalculateValidation()
{
std::cout << "Calculate validation" << std::endl;
};
};
template <class T>
class Handler : public IBase<T>, public Validate
{
public:
void ValidateCallback() override
{
std::cout << "ValidateCallback" << std::endl;
CalculateValidation();
};
void Receive()
{
IBase<T>::RxCallback();
};
void Send()
{
IBase<T>::Send();
}
};
int main()
{
Handler<B1> handler1;
handler1.Receive();
handler1.Send();
std::cout << std::endl;
Handler<B2> handler2;
handler2.Receive();
handler2.Send();
}
Output:
Parse C1
DoSomething other than B2
RxCompleteCallback
DoSomething B1
ValidateCallback
Calculate validation
Parse C2
DoSomething other than B1
RxCompleteCallback
DoSomething B2
ValidateCallback
Calculate validation
There are several ways to do this in C++. It's hard to say what the best way is, it depends on how you will use it, and the example you gave is too simple to recommend a specific way. Normally, I'd say you want to derive your protocol-specific classes from Handler, instead of the other way around, so you'd write:
class Handler {
public:
virtual void Receive() {};
virtual void Send() {};
};
class B1: public Handler {
virtual void Receive() {
...
}
virtual void Send() {
...
}
};
int main() {
B1 handler1;
handler1.Receive();
...
}
The main issue here is that you need to use virtual member functions here, otherwise the base class doesn't know which derived class's implementation to call. But it does allow you to pass a Handler * as an argument to another function, which will then work with any derived class without needing any templating.
Another option is to use the curiously recurring template pattern, which would look like:
template <typename T>
class Handler {
void Receive() {
static_cast<T*>(this)->Receive();
}
void Send() {
static_cast<T*>(this)->Send();
}
};
class B1: public Handler<B1>
{
void Receive() {
...
}
void Send() {
...
}
};
int main() {
B1 handler1;
handler1.Receive();
...
}
This avoids virtual methods.
It is also quite similar to your class Handler, but it has the advantage that it doesn't need the T *object member variable.
I want an attribute in a C++ class be an uninstantiated class from a particular class heirachy. All members of this class heirachy would then implement the same method, meaning I could instantiate the object and then use the method when the situation calls for it. Here's some code (that doesn't compile) demonstrating what I mean:
#include <iostream>
using namespace std;
class Event {
public:
Event() = default;
virtual void go() = 0;
};
class EventA : Event {
public:
EventA() = default;
void go(){
cout << "Running event A"<< endl;
}
};
class EventB : Event {
public:
EventB() = default;
void go(){
cout << "Running event B"<< endl;
}
};
class Situation{
private:
Event* current_event = &EventA; //Problematic code: EventA does not refer to a value
public:
Situation() = default;
void setEvent(Event* event){
current_event = event;
}
void runEvent(){
current_event.go();
}
};
int main() {
Situation situation;
situation.runEvent();
situation.setEvent(&EventB);
situation.runEvent();
return 0;
};
No, you cannot form pointers to classes, and you cannot invoke [non-static] member functions without a class instance (object).
You should probably std::make_unique an instance of the type you want to use.
Don't forget to give your base a virtual destructor, since you're doing polymorphism things.
A static alternative would be std::variant.
In two places, you seem to be doing what could be described as trying to take a pointer from a type:
Event* current_event = &EventA;
and
situation.setEvent(&EventB);
This doesn't work and is not really a thing with proper meaning in C++. What you are trying to do could be implemented in 3 different ways I can think of.
Method 1: instead of having a class, you can have a function pointer, and pass the function pointer as parameter:
#include <iostream>
using namespace std;
void eventA_go(){
cout << "Running event A"<< endl;
}
void eventB_go(){
cout << "Running event B"<< endl;
}
class Situation{
private:
using EventFunctionPtr = void (*)();
EventFunctionPtr current_event = &eventA_go;
public:
Situation() = default;
void setEvent(EventFunctionPtr event){
current_event = event;
}
void runEvent(){
current_event();
}
};
int main() {
Situation situation;
situation.runEvent();
situation.setEvent(&eventB_go);
situation.runEvent();
return 0;
};
Method 2: you can make this code a little more generic, by allowing any type of callable in your Situation class, not only function pointers:
#include <iostream>
#include <functional>
using namespace std;
void eventA_go(){
cout << "Running event A"<< endl;
}
void eventB_go(){
cout << "Running event B"<< endl;
}
class Situation{
private:
std::function<void ()> current_event = eventA_go;
public:
Situation() = default;
template <typename F>
void setEvent(F&& event){
current_event = event;
}
void runEvent(){
current_event();
}
};
int main() {
Situation situation;
situation.runEvent();
situation.setEvent(&eventB_go);
situation.runEvent();
return 0;
};
Method 3: you can go back to your original idea of having a base class that must be implemented to provide a go() method, but in this case you will actually have to make sure the objects you are calling do exists. A possible way to do it is with std::unique_ptr:
#include <iostream>
#include <memory>
using namespace std;
class Event {
public:
Event() = default;
virtual ~Event() = default;
virtual void go() = 0;
};
class EventA : public Event {
public:
EventA() = default;
void go(){
cout << "Running event A"<< endl;
}
};
class EventB : public Event {
public:
EventB() = default;
void go(){
cout << "Running event B"<< endl;
}
};
class Situation{
private:
std::unique_ptr<Event> current_event = std::make_unique<EventA>();
public:
Situation() = default;
void setEvent(std::unique_ptr<Event>&& event){
current_event = std::move(event);
}
void runEvent(){
current_event->go();
}
};
int main() {
Situation situation;
situation.runEvent();
situation.setEvent(std::make_unique<EventB>());
situation.runEvent();
return 0;
};
Notice that, in this case, the destructor of the abstract class must be virtual, and the inheritance must be public.
You seem to be confused about classes and variables. Which object would situation.runEvent(); run on? I think you want to publicly derive the classes from Event and initialize current_event when you need to. You don't need to do anything like current_event = &EventB. C++ automagically determines which function is needed to be called based on what current_event is dynamically pointing to. Here's what I think you meant to do:
#include <cassert>
#include <iostream>
class Event {
public:
virtual void go() = 0;
virtual ~Event() = default; // Don't forget the virtual destructor
};
class EventA : public Event {
public:
void go() override { std::cout << "Running event A" << std::endl; }
};
class EventB : public Event {
public:
void go() override { std::cout << "Running event B" << std::endl; }
};
class Situation {
private:
Event* current_event = nullptr;
public:
void setEvent(Event* event) { current_event = event; }
void runEvent() {
assert(current_event);
current_event->go();
}
};
int main() {
Situation situation;
EventA a;
EventB b;
situation.setEvent(&a);
situation.runEvent();
situation.setEvent(&b);
situation.runEvent();
}
I have been looking for a way to use both templating and polymorphism at the same time. Here's a simplified version of my problem:
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
//*******************************************************************
//*******************************************************************
struct DerivedStuff1
{
static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2
{
static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
template<typename StuffType> virtual void eval() const = 0;
};
class DerivedClass1 : public BaseClass
{
public:
template<typename StuffType> virtual void eval() const
{
std::cout << "We are in DerivedClass1: ";
StuffType::eval();
}
};
class DerivedClass2 : public BaseClass
{
public:
template<typename StuffType> virtual void eval() const
{
std::cout << "We are in DerivedClass2: ";
StuffType::eval();
}
};
int main()
{
BaseClass* c1 = new DerivedClass1;
c1->eval<DerivedStuff1>();
c1->eval<DerivedStuff2>();
BaseClass* c2 = new DerivedClass2;
c2->eval<DerivedStuff1>();
c2->eval<DerivedStuff2>();
return 0;
}
This code does not compile because virtual template functions are not allowed in C++. I found a few approaches to tackle this problem (CRTP, etc.) but none of them were really satisfying. Is there no elegant way to get around that issue?
The visitor pattern turns run-time polymorphism on its side and makes runtime-polymorphic function templates possible. It has other legitimate uses apart from templatisation, so I guess you can call it somewhat elegant.
Your example can look as follows:
#include <iostream>
class DerivedStuff1 {
public:
static void eval() { std::cout << "Evaluating DerivedStuff1\n"; }
};
class DerivedStuff2 {
public:
static void eval() { std::cout << "Evaluating DerivedStuff2\n"; }
};
class DerivedClass1; class DerivedClass2;
class BaseClassVisitor {
public:
virtual void visit(DerivedClass1&) = 0;
virtual void visit(DerivedClass2&) = 0;
};
class BaseClass {
public:
virtual void accept(BaseClassVisitor& v) = 0;
};
class DerivedClass1 : public BaseClass
{
public:
virtual void accept(BaseClassVisitor& v) { v.visit(*this); }
};
class DerivedClass2 : public BaseClass
{
public:
virtual void accept(BaseClassVisitor& v) { v.visit(*this); }
};
template <typename StuffType>
class EvalVisitor : public BaseClassVisitor
{
virtual void visit(DerivedClass1&) {
std::cout << "We are in DerivedClass1: ";
StuffType::eval();
}
virtual void visit(DerivedClass2&) {
std::cout << "We are in DerivedClass2: ";
StuffType::eval();
}
};
int main()
{
EvalVisitor<DerivedStuff1> e1;
EvalVisitor<DerivedStuff2> e2;
BaseClass* c1 = new DerivedClass1;
c1->accept(e1);
c1->accept(e2);
BaseClass* c2 = new DerivedClass2;
c2->accept(e1);
c2->accept(e2);
return 0;
}
Demo
Of course all shortcomings of Visitor apply here.
You could reinvent the vtable and resolve the function pointer at run time. You will, however, have to explicitely instantiate the template on the derived class, but I don't see any approach to this that won't require that.
Quick and dirty example:
#include <map>
#include <iostream>
class Base {
public:
typedef void (Base::*eval_ptr)();
using eval_vtable = std::map<std::type_index, eval_ptr>;
Base(eval_vtable const& eval_p) : eval_ptrs(eval_p) {}
template<typename T>
void eval() {
auto handler = eval_ptrs.find(type_index(typeid(T)));
if(handler != eval_ptrs.end()) {
auto handler_ptr = handler->second;
(this->*handler_ptr)();
}
}
eval_vtable const& eval_ptrs;
};
class Derived : public Base {
public:
Derived()
: Base(eval_functions) {}
template<typename T>
void eval_impl() {
std::cout << typeid(T).name() << "\n";
}
static eval_vtable eval_functions;
};
Base::eval_vtable Derived::eval_functions = {
{ type_index(typeid(int)), eval_ptr(&Derived::eval_impl<int>) },
{ type_index(typeid(float)), eval_ptr(&Derived::eval_impl<float>) },
{ type_index(typeid(short)), eval_ptr(&Derived::eval_impl<short>) },
};
int main(int argc, const char* argv[]) {
Derived x;
Base * x_as_base = &x;
x_as_base->eval<int>(); // calls Derived::eval_impl<int>()
return 0;
}
This won't be exactly fast, but it will give you the closest thing to templated virtual functions that I can think of.
Edit: For the record I don't advocate anyone use this. I would much rather revisit the design to avoid being painted in this particular corner in the first place. Please consider my answer as an academic solution to a theoretical problem, not an actual engineering recommendation.
Since virtual template methods in C++ arent allowed, you can make a class template and call static function of class template param.
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
//*******************************************************************
//*******************************************************************
struct DerivedStuff1
{
static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2
{
static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
virtual void eval() const = 0;
};
template<typename StuffType>
class DerivedClass1 : public BaseClass
{
public:
virtual void eval() const
{
std::cout << "We are in DerivedClass1: ";
StuffType::eval();
}
};
template<typename StuffType>
class DerivedClass2 : public BaseClass
{
public:
virtual void eval() const
{
std::cout << "We are in DerivedClass2: ";
StuffType::eval();
}
};
int main()
{
BaseClass* c1 = new DerivedClass1<DerivedStuff1>;
c1->eval();
c1 = new DerivedClass1<DerivedStuff2>;
c1->eval();
BaseClass* c2 = new DerivedClass2<DerivedStuff1>;
c2->eval();
c2 = new DerivedClass2<DerivedStuff2>;
c2->eval();
// deletes
return 0;
}
Output
We are in DerivedClass1: evaluating DerivedStuff1
We are in DerivedClass1: evaluating DerivedStuff2
We are in DerivedClass2: evaluating DerivedStuff1
We are in DerivedClass2: evaluating DerivedStuff2
You cannot mix templates (compile time) and polymorphic (runtime). That's it.
So, a posible workaround is remove templates. For example, it could take a function pointer or just more polymorphism:
//*******************************************************************
//*******************************************************************
struct InterfaceStuff{
virtual void eval() = 0;
}
struct DerivedStuff1 : public InterfaceStuff
{
void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2 : public InterfaceStuff
{
void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
virtual void eval(InterfaceStuff* interface) const = 0;
};
class DerivedClass1 : public BaseClass
{
public:
virtual void eval(InterfaceStuff* interface) const
{
std::cout << "We are in DerivedClass1: ";
interface->eval();
}
};
class DerivedClass2 : public BaseClass
{
public:
virtual void eval(InterfaceStuff* interface) const
{
std::cout << "We are in DerivedClass2: ";
interface->eval();
}
};
Another posible workaround is remove polymorphism, just use more templates:
struct DerivedStuff1
{
static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2
{
static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
template<typename Eval,typename StuffType> void eval() const
{
Eval::eval();
StuffType::eval();
}
};
class DerivedClass1 : public BaseClass
{
};
class DerivedClass2 : public BaseClass
{
};
One way of another, you have to choose one.