简体   繁体   中英

How I can keep track of all the functions defined with a macro to later call them all at once?

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?

Well you can do some horrid things like the code below (just an outline of the idea). Should you really do it or not is up to you however.

static std::vector<std::function<void()>> g_vec;
class Reg
{
public:
    Reg(std::function<void()> f) { g_vec.push_back(f); }
};

// insert __declspec(selectany) for your compiler and do some better function passing around, maybe C style
#define FUN(x) void v##x(); inline static Reg r##x { []{ v##x(); } }; void v##x()
FUN(a)
{
    std::cout << "a\n";
}
FUN(b)
{
    std::cout << "b\n";
}

int main(int argc, const char * argv[])
{
    for (auto& f : g_vec)
        f();
}

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() ).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM