I have the following code to define new functions by using a macro
#include <iostream>
#define CONCAT(x, y) x##y
#define PREFIX_COUNTER(prefix, counter) CONCAT(prefix, counter)
#define FUNC() void PREFIX_COUNTER(func_, __COUNTER__)()
FUNC() {
std::cout << "first func" << std::endl;
}
FUNC() {
std::cout << "second func" << std::endl;
}
int main(int, char **) {
func_0();
func_1();
return 0;
}
Each call to FUNC
will define a new function like func_0
, what I need to do now is to call to all the functions defined by func like this:
int main(int, char **) {
CALL_ALL_FUNC(); // this will call func_0 and func_1
return 0;
}
Could be possible to append the name of every new FUNC call into something like a vector so later I can iterate it? Does the preprocessor has something like that?
CodePudding user response:
I'm not entirely sure what you are trying to do here, but I don't think that a macro is the correct approach.
__COUNTER__
increments every time it appears, so you can't ever actually check how many functions are defined (as the number will keep incrementing). Likewise, if you (or a library) uses it elsewhere, there isn't any way to tell how many functions were created and how many times __COUNTER__
was incremented by something else.
A possible alternative solution to your problem is to create an std::vector
of function pointers. You can also combine this with lambda expressions and wrap it in a singleton or a static class to get somewhat close to what you want to define:
//DynamicFunctions.h
#include <vector>
#include <functional>
class DynamicFunctions {
public:
static void add(std::function<void()> const& function) {
_functions.push_back(function);
};
static void call(int index) {
//TODO: range checking
_functions[index]();
}
static void runAll() {
for (auto const& func : _functions) {
func();
}
};
private:
static std::vector<std::function<void()>> _functions;
};
std::vector<std::function<void()>> DynamicFunctions::_functions = std::vector<std::function<void()>>();
//main.cpp
#include <iostream>
#include "DynamicFunctions.h"
int main() {
DynamicFunctions::add([]() { std::cout << "Functions[0]" << std::endl; });
DynamicFunctions::add([]() { std::cout << "Functions[1]" << std::endl; });
DynamicFunctions::add([]() { std::cout << "hi!" << std::endl;});
DynamicFunctions::call(2);
DynamicFunctions::runAll();
return 0;
}
This way, whenever you needed to create a dynamic function, instead of using the macro you would call DynamicFunctions::add
. To run a function, instead of calling func_0
, you would pass that index to DynamicFunctions::call(0)
. This way, as it's all stored in a std::vector
, you can easily iterate through them when you need to call DynamicFunctions::runAll
CodePudding user response:
Since Catch2 was mentioned, here is an example based off of the macros there.
#include <iostream>
#include <vector>
struct Func;
std::vector<Func*> func_group;
struct Func {
Func() {
func_group.push_back(this);
}
virtual void action() = 0;
};
#define CONCAT(x, y) x##y
#define PREFIX_COUNTER(prefix, counter) CONCAT(prefix, counter)
#define UNIQUE_FUNC(id) \
struct PREFIX_COUNTER(Func_, id) : public Func {\
void action();\
} PREFIX_COUNTER(func_instance_, id);\
void PREFIX_COUNTER(Func_, id)::action()
#define FUNC() UNIQUE_FUNC(__COUNTER__)
FUNC() {
std::cout << "first func" << std::endl;
}
FUNC() {
std::cout << "second func" << std::endl;
}
int main() {
for (auto func : func_group)
func->action();
return 0;
}
- A new derived class is defined for each
FUNC
macro. - It initializes itself and adds itself to a vector.
- The macro leads into defining the body of a function that can be called from the base class later. (
func->action()
).