C++ code generation: create a factory for function pointers

不羁的心 提交于 2019-12-06 13:58:55

问题


I have a long and steadily growing list of (non-member) functions and I need to select one of the functions from this list at runtime (based on a command line argument). At the moment I do this using a factory function which takes a string (the name of the function) and returns a pointer to the function. However this means I have to edit the factory function every time I add a new function (which is both annoying and a violation of the DRY principle).

I would like to somehow generate the factory function by parsing the source code of the list of functions (inspired by reading the code generation section of The Pragmatic Programmer last night). However it seems that it is very hard to parse C++ correctly and I would rather not make my project depend on libclang just for this.

So my question is: how can I select a function by name at runtime without introducing heavyweight dependencies?

Is it "safe" to only partially parse the c++ code (e.g. just using a regex to extract function names by matching something that looks like a set of function arguments)?

Are there any other (portable and not too hacky) ways of doing this without manually writing the selection code?

edit: Forgot to say: I'm not allowed to use C++11, so no lambda functions unfortunately.


回答1:


Here is a fully working example :

#include <iostream>
#include <map>

namespace detail {
    struct FuncPtrMap {
        friend struct FuncPtrRegisterer;
        using FuncPtr = void(*)();
        static std::map<std::string, FuncPtr> const &getMap() {
            return getWritableMap();
        }

    private:
        // SIOF-proof singleton
        static std::map<std::string, FuncPtr> &getWritableMap() {
            static std::map<std::string, FuncPtr> theMap;
            return theMap;
        }
    };

    // Each static instance will register one function pointer
    struct FuncPtrRegisterer {
        FuncPtrRegisterer(FuncPtrMap::FuncPtr funcPtr, char const *funcName) {
            FuncPtrMap::getWritableMap().emplace(funcName, funcPtr);
        }
    };
}

// Public access to the function pointers map
auto const &gFunctionPointersMap = detail::FuncPtrMap::getMap();

#define DO_CAT(A, B) A##B
#define CAT(A, B) DO_CAT(A, B)

// Registering macro : defines a static registerer
// with a (hopefully) unique name.
#define REGISTER_FUNC(NAME) detail::FuncPtrRegisterer \
    CAT(fpreg, __COUNTER__) (&NAME, #NAME)


//
// Test
//

void myFunc1() {
    std::cout << "func1\n";
}
REGISTER_FUNC(myFunc1);

void myFunc2() {
    std::cout << "func2\n";
}
REGISTER_FUNC(myFunc2);

int main()
{
    for(auto const &kv : gFunctionPointersMap) {
        std::cout << "Calling " << kv.first << " : ";
        kv.second();
    }

    return 0;
}

Prints :

Calling myFunc1 : func1
Calling myFunc2 : func2

Just put a REGISTER_FUNC(func) after each function you wish to register. You only need the declaration of the function, not its definition. Beware that this will not work in header files though.

Afterwards, you can access gFunctionPointersMap at any time from the very start of main :)

Edit : C++03 version here (nothing much changes really).



来源:https://stackoverflow.com/questions/25488748/c-code-generation-create-a-factory-for-function-pointers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!