pazamelin
pazamelin

Reputation: 3

Macro for calling a series of macro-generated functions with similar names (i.e. f_0, f_1, f_2, ...)

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

Answers (2)

KamilCuk
KamilCuk

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

Alan Birtles
Alan Birtles

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

Related Questions