Reputation: 3
I got stuck with quite peculiar problem, and I at the moment have no idea how to solve it.
I am using the following block of macros to generate functions with similar names:
#define CONCAT_IMPLEMENTATION(arg1, arg2) arg1 ## arg2
#define CONCAT(arg1, arg2) CONCAT_IMPLEMENTATION(arg1, arg2)
#define UNIQUE_FUNCTION_NAME(index) CONCAT(f_, index)
#define GENERATE_FUNCTION() void UNIQUE_FUNCTION_NAME(__COUNTER__) ()
So code like this:
GENERATE_FUNCTION()
{
std::cout << "first function" << std::endl;
}
GENERATE_FUNCTION()
{
std::cout << "second function" << std::endl;
}
is replaced with:
void f_0 ()
{
std::cout << "first function" << std::endl;
}
void f_1 ()
{
std::cout << "second function" << std::endl;
}
Is there any way to implement a macro or a function that would call all the generated functions?
That is to say it would call functions from f_0 to f_N, where N is a current value of __COUNTER__
macro.
Something like that:
#define RUN_ALL_GENERATED_FUNCTIONS() // ??? //
int main()
{
RUN_ALL_GENERATED_FUNCTIONS();
return 0;
}
Looks rather impossible up to me. Could you give me any suggestions, please?
Upvotes: 0
Views: 132
Reputation: 141758
There is no magic in preprocessor. To overload, you have to enumerate all possible cases anyway.
#define RUN_ALL_GENERATED_FUNCTIONS_1() UNIQUE_FUNCTION_NAME(0)();
#define RUN_ALL_GENERATED_FUNCTIONS_2() RUN_ALL_GENERATED_FUNCTIONS_1()UNIQUE_FUNCTION_NAME(1)();
#define RUN_ALL_GENERATED_FUNCTIONS_3() RUN_ALL_GENERATED_FUNCTIONS_2()UNIQUE_FUNCTION_NAME(2)();
#define RUN_ALL_GENERATED_FUNCTIONS_4() RUN_ALL_GENERATED_FUNCTIONS_3()UNIQUE_FUNCTION_NAME(3)();
#define RUN_ALL_GENERATED_FUNCTIONS() do{ CONCAT(RUN_ALL_GENERATED_FUNCTIONS_, __COUNTER__)() }while(0)
int main() {
RUN_ALL_GENERATED_FUNCTIONS();
// do{ f_0();f_1(); }while(0);
}
Note that __COUNTER__
is non-portable, you might as well use descriptive function names (and readability of the code is important and __func__
will expand to something meaningful) and put pointers to these functions into a custom linker section with __attribute__
, then iterate over that section to execute all functions. It's typical to do that - within testing frameworks and in kernel, with .init
and .fini
etc. sections.
Upvotes: 0
Reputation: 36488
There is no need for macros here, just push function pointers into a vector then you can iterate through the vector calling each function in turn. One possible implementation would be:
#include <vector>
#include <functional>
#include <iostream>
struct Functions
{
static std::vector<std::function<void()>> functions;
template <typename T>
static T make_function(T f)
{
functions.push_back(f);
return f;
}
static void call()
{
for (auto& f : functions)
{
f();
}
}
};
std::vector<std::function<void()>> Functions::functions;
auto f_1 = Functions::make_function([]
{
std::cout << "first function" << std::endl;
});
auto f_2 = Functions::make_function([]
{
std::cout << "second function" << std::endl;
});
int main()
{
f_1();
f_2();
Functions::call();
}
If you really need to you could still wrap Functions::make_function
into a macro.
Upvotes: 2