Reputation: 47
I'm working on a project executed on an ESP32 micro controller (c++11) and I would like to implement a class method that could take Class References (not instances of those classes) as arguments in order to execute static methods of those classes.
I manage to implement the following working solution :
#include <iostream>
class Model
{
public:
static void foo()
{
std::cout << "Model.foo invoked" << std::endl;
};
};
class ModelA: public Model
{
public:
static void foo()
{
std::cout << "ModelA.foo invoked" << std::endl;
};
};
class ModelB: public Model
{
public:
static void foo()
{
std::cout << "ModelB.foo invoked" << std::endl;
};
};
class Manager
{
public:
template <class T = Model>
void callFoo()
{
T::foo();
}
template<class T = Model, class ... args>
void setup()
{
callFoo<T>();
callFoo<args...>();
}
};
int main()
{
Manager manager;
manager.setup<ModelA, ModelB>();
return 0;
}
The output meets the expected result :
ModelA.foo invoked
ModelB.foo invoked
But I have the feeling that this approach is at best a poor hack...
Does someone has a better way to implement this (ideally without using a template) ?
Thank you in advance.
Vincent.
Upvotes: 0
Views: 570
Reputation: 4143
You want to use typeclasses as parameters. Not currently available in "C++".
Yet, for your specific case, since all static methods have the same function prototype, or function signature, you could do some workarounds.
First, change each static method into a virtual method:
#include <iostream>
class Model
{
public:
virtual Foo(void* Args)
{
str::cout << "method Model.DoFoo( ) invoked. << std::endln;
} // DoFoo
}; // class Model
class ModelA: Model
{
public:
virtual Foo(void* Args)
{
str::cout << "method ModelA.DoFoo( ) invoked. << std::endln;
} // DoFoo
}; // class ModelA
class ModelB: Model
{
public:
virtual Foo(void* Args) override
{
str::cout << "method ModelB.DoFoo( ) invoked << std::endln;
} // DoFoo
}; // class ModelB
Second, add a local function, not a method, to generate an instance of each class as a result:
Model* ModelFactory( )
{
Model* M = new Model ( );
return M;
} // ModelFactory
Model* ModelAFactory( )
{
Model* M = new ModelA( );
return M;
} // ModelFactory
Model* ModelBFactory( )
{
Model* M = new ModelB ( );
return M;
} // ModelFactory
Three, your Manager
class, instead of "variadic" or "..." parameters, you will add a vector as a single parameter, to store references to those factory functions.
And a parameter to store that vector.
#include <vector>
typedef
Model* (*Factory) (void* Args);
class Manager
{
public:
std::vector<Factory>* Factories;
void setup(std::vector<Factory>* AFactories)
{
this.Factories = AFactories;
} // setup
} ; // class Manager
Note that the factories work as typeclasses parameters.
Four, a method to the Manager
class to retrieve each factory from the vector, execute it, generate an instance, call the replacement virtual method, and later, dispose the instance.
class Manager
{
public:
std::vector<Factory>* Factories;
void setup(std::vector<Factory>* AFactories)
{
this.Factories = AFactories;
} // setup
void run(void* Args)
{
for (Factory EachFactory : this.Factories)
{
Model* M = EachFactory( );
M->Foo(Args);
delete M;
} // for
} // void
} ; // class Manager
Five, build the example:
int main( )
{
Manager* M = new Manager( );
// prepare compiletime list of classes
std::vector<Factory>* Factories =
new std::vector<Factory>*(2);
Factories->insert(&ModelAFactory);
Factories->insert(&ModelBFactory);
// assign list to Manager
M->setup(Factories);
// execute each class method
// with same parameters
M->run( nullptr );
// drop list
delete Factories ( );
delete M;
} // main
Your Model
class and subclasses may have other operations, not related at all, and still do not conflict, with the static
methods replaced by virtual
methods.
Note, that newer versions of C++ standard can do something similar to this with concepts, and variadic arguments' templates.
Upvotes: 0
Reputation: 34628
If you want to dispatch static member functions of any type based on references of that type, you can easily do this by (slightly) abusing function template parameter inference:
template <typename T>
void call(T const& = *static_cast<T const*>(nullptr)) {
T::foo();
}
struct Magic {
static void foo() {}
};
struct MoreMagic {
static void foo() {}
};
int main() {
call<Magic>();
call(MoreMagic());
MoreMagic m;
call(m);
}
Upvotes: 1