c++代码生成:为函数指针创建工厂

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

本文关键字:指针 创建 工厂 函数 代码生成 c++      更新时间:2023-10-16

我有一个长而稳定增长的(非成员)函数列表,我需要在运行时(基于命令行参数)从该列表中选择一个函数。目前我使用一个工厂函数,它接受一个字符串(函数的名称)并返回一个指向函数的指针。然而,这意味着每次添加新函数时都必须编辑工厂函数(这既烦人又违反了DRY原则)。

我想以某种方式通过解析函数列表的源代码来生成工厂函数(灵感来自昨晚阅读the Pragmatic Programmer的代码生成部分)。然而,似乎很难正确解析c++,我宁愿不让我的项目依赖libclang只是为了这个。

所以我的问题是:我如何在运行时按名称选择函数而不引入重量级依赖关系?

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

在不手动编写选择代码的情况下,是否有其他(可移植且不太黑客的)方法来做到这一点?

编辑:忘了说:我不允许使用c++ 11,所以很遗憾没有lambda函数。

下面是一个完整的工作示例:

#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 << "func1n";
}
REGISTER_FUNC(myFunc1);
void myFunc2() {
    std::cout << "func2n";
}
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)。您只需要函数的声明,而不需要它的定义。但要注意,这在头文件中不起作用。

之后,您可以从main开始的任何时间访问gFunctionPointersMap:)

编辑:c++ 03版本在这里(实际上没有什么变化)。