My goal is to iterate over all functions of the namespace until a function returns me a valid strategy(enum). Each function can take different arguements.
enum class strategyType
{
Strategy1,
Strategy2,
Strategy3,
Strategy4,
Strategy5,
InvalidStrategy
}
namespace allFunctionStrategy
{
strategyType algorithmMl(int v1,int v2);
strategyType algorithmHeuristic(int v3,string s1);
strategyType algorithmHeuristic(string s1,string s2);
... n such function's
}
class strategyContext
{
int v1,v2,v3;
string s1,s2;
/*i want to add iterator logic here*/
}
CodePudding user response:
Write a function that calls them:
void strategyContext::execute() {
if (algorithmM1(v1, v2) != strategyType::InvalidStrategy)
;
else if (algorithmHeuristic(v3, s1) != strategyType::InvalidStrategy)
;
else if (algorithmHeuristic(s1, s2) != strategyType::InvalidStrategy)
;
else
throw no_valid_strategy();
}
or, if the word "looping" was meant as a requirement, write wrappers and put the function pointers into an array:
strategyType strategyContext::wrap_algorithmM1() {
return algorithmM1(v3, s1);
}
strategyType strategyContext::wrap_algorithmHeuristic1() {
return algorithmHeuristic(v3, s1);
}
strategyType strategyContext::wrap_algorithmHeuristic2() {
return algorithmHeuristic(s1, s2);
}
typedef strategyType (strategyContext::*fptr)();
fptr pointers[] = {
&strategyContext::wrap_algorithmM1,
&strategyContext::wrap_algorithmHeuristic1,
&strategyContext::wrap_algorithmHeuristic2
};
void strategyContext::execute() {
for (auto iter = std::begin(pointers);
iter != std::end(pointers);
iter) {
if ((this->*(*iter))() != strategyType::InvalidStrategy)
return;
}
throw no_valid_strategy();
}
CodePudding user response:
Okay, first things first, you probably don't need to iterate over every function in the namespace. I'm going to show you how to use two macros to implement basic reflection, but you should probably also rethink what you're trying to do. Also, this is going to be really messy code.
First, we want every function to take the same parameters and return the same thing. For your use case, you can add all the parameters that the functions could use to a struct.
struct PossibleParams
{
//You can expand this if you want
int x, y, z;
};
struct Output {};
Next, we need a place to store the functions. Import functional
and unordered_map
and add the following macro.
#define ReflectableNamespace(name) namespace __REFLECTABLE__\
{ struct __NAMESPACE_ ## name ## __ { inline static std::unordered_map<std::string, std::function<Output(PossibleParams)>> funcs; }; \
struct __ ## name ## _MAP_ADDER__ \
{\
__ ## name ## _MAP_ADDER__ (const std::string& Name, std::function<Output(PossibleParams)> func) { __NAMESPACE_ ## name ## __::funcs[Name] = func; }\
};\
}\
namespace name
Here's what that macro does:
- Defines an
unordered_map
that maps between the function name and the function in the__REFLECTABLE__
namespace. - Defines a struct that will let us add the function to this map at startup through its constructor
- Begins the namespace that you're trying to make
This second macro will declare a function that can be iterated over and add it to the functions map.
#define ReflectableFunction(namespace, name) Output name (PossibleParams);\
struct __NAMESPACE_ ## namespace ## _ ## name ## _adder__ {\
inline static const __REFLECTABLE__::__ ## namespace ## _MAP_ADDER__ Adder = __REFLECTABLE__::__ ## namespace ## _MAP_ADDER__ (#name, name);\
}
This second struct declares a function that returns an Output
and takes a PossibleParams
as a parameter. It then creates an instance of that namespace's map adder object so that the function will be added to the namespace's map on startup. Since everything is inline, this should be able to be used in header files.
To call one of these functions, just use __REFLECTABLE__::__NAMESPACE_YourNamespace__::funcs["TheFunction"]({...});
Full working example:
struct PossibleParams
{
//Can expand this if you want
int x, y, z;
};
struct Output {};
#include <unordered_map>
#include <functional>
#define ReflectableNamespace(name) namespace __REFLECTABLE__\
{ struct __NAMESPACE_ ## name ## __ { inline static std::unordered_map<std::string, std::function<Output(PossibleParams)>> funcs; }; \
struct __ ## name ## _MAP_ADDER__ \
{\
__ ## name ## _MAP_ADDER__ (const std::string& Name, std::function<Output(PossibleParams)> func) { __NAMESPACE_ ## name ## __::funcs[Name] = func; }\
};\
}\
namespace name
#define ReflectableFunction(namespace, name) Output name (PossibleParams);\
struct __NAMESPACE_ ## namespace ## _ ## name ## _adder__ {\
inline static const __REFLECTABLE__::__ ## namespace ## _MAP_ADDER__ Adder = __REFLECTABLE__::__ ## namespace ## _MAP_ADDER__ (#name, name);\
}
#include <iostream>
ReflectableNamespace(MyNamespace)
{
ReflectableFunction(MyNamespace, func);
Output func(PossibleParams)
{
std::cout << "Hello" << std::endl;
return {};
}
}
int main()
{
std::cout << __REFLECTABLE__::__NAMESPACE_MyNamespace__::funcs.size() << std::endl;
__REFLECTABLE__::__NAMESPACE_MyNamespace__::funcs["func"]({});
return 0;
}
One last thing. If you're planning to iterate through this map a lot, it may be better to replace it with a normal map
since it may be faster to iterate through. Or, if you don't care about the function's name, you could consider replacing the map with a vector. I hope this helps!