本文介绍了C ++代码生成:为函数指针创建工厂的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的(非成员)函数列表越来越长,而且还在不断增长,我需要在运行时从此列表中选择一个函数(基于命令行参数).目前,我使用工厂函数执行此操作,该函数接受字符串(函数名称)并返回指向该函数的指针.但是,这意味着每次添加新功能(这既烦人又违反 DRY原理).

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

我想通过解析函数列表的源代码以某种方式生成工厂函数(灵感来自阅读实用程序员(昨晚).但是,似乎很难正确地解析C ++,我不想让我的项目仅依赖于libclang.

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?

仅部分解析c ++代码是否安全"(例如,仅使用正则表达式通过匹配看起来像一组函数参数的东西来提取函数名)?

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?

忘了说:我不允许使用C ++ 11,因此不幸的是没有lambda函数.

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

推荐答案

下面是一个完全有效的示例:

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;
}

打印:

Calling myFunc1 : func1
Calling myFunc2 : func2

只需在要注册的每个功能后放置一个REGISTER_FUNC(func).您只需要函数的声明,而不需要其定义.请注意,尽管如此,这在头文件中将不起作用.

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.

此后,您可以从main刚开始时随时访问gFunctionPointersMap:)

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

C ++ 03版本此处(实际上没有多大变化).

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

这篇关于C ++代码生成:为函数指针创建工厂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-16 07:21