使用 std::string 调用 C++11 中的函数

Ane*_*ees 0 c++ linux windows c++11

我想使用字符串值来调用函数。这可能吗?有人可以展示一些实现吗?我会很感激。

class obj {
    int num1;
    int num2;
}

int func1(obj o) {
   return o.num1 + o.num2;
}

// This is an example data set. This map would be populated with values in the map below with some piece of code.
std::map<std::string, std::string> funcNameMap = {{"func1", "func1"}};

int someFunction(std::string funcName, obj o) {
    // Get the value associated with the string "funcName" i.e. "func1". 
    // Calls function "func1" with value "o" and returns the value.
}

int main(){
   obj o;
   o.num1 = 1;
   o.num2 = 2;
   auto x = someFunciton("func1", o);
   std::cout << x << std::endl;
   return 0;
}


Run Code Online (Sandbox Code Playgroud)

我正在编写一个收集指标数据的程序。我想针对特定指标执行特定函数。我会将所有函数命名为与指标名称相同的名称,这样当我将指标名称作为输入(字符串)时,它将执行特定的函数。我不想使用 if-else 来根据输入的指标名称执行函数,因为我的程序正在收集一百多个指标。如果有 if-else 的话,看起来会很尴尬。这就是为什么我尝试这样做。

想要适用于 windows/linux 操作系统的东西

ILS*_*ILS 5

一种解决方案是创建从函数名称到函数本身的映射。我们知道在C/C++中函数就是一个指针,所以在确认了函数指针的类型之后我们就可以很容易的做到这一点。在您的情况下,目标函数类型是int (*)(obj).

代码片段:

#include <iostream>
#include <map>
#include <string>

class obj {
  public:
    int num1;
    int num2;
};

int func1(obj o) {  // type: int (*)(obj)
    return o.num1 + o.num2;
}

// create the mapping from name to function
std::map<std::string, int (*)(obj)> funcNameMap = {{"func1", func1}};

int someFunction(std::string funcName, obj o) {
    // Get the value associated with the string "funcName" i.e. "func1". 
    // Calls function "func1" with value "o" and returns the value.
    auto fn = funcNameMap.at(funcName);
    return fn(o);
}

int main(){
   obj o;
   o.num1 = 1;
   o.num2 = 2;
   auto x = someFunction("func1", o);
   std::cout << x << std::endl;
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

编辑:根据注释更新,使用动态共享库以避免手动创建映射。我假设你使用的是Linux。

首先,将类定义和目标函数的类型移动到单独的标头中obj.hpp

class obj {               
  public:                 
    int num1;             
    int num2;             
};                        
// type of target functions
typedef int (*ftype)(obj);
Run Code Online (Sandbox Code Playgroud)

将目标函数收集到一个单独的文件中functions.cpp以构建动态共享库。

#include "obj.hpp"

extern "C"
int func1(obj o) {
    return o.num1 + o.num2;
}
extern "C"
int func2(obj o) {
    return o.num1 - o.num2;
}
Run Code Online (Sandbox Code Playgroud)

在第三个文件中main.cpp,我们根据函数名称从库中检索函数。

#include <iostream>
#include <map>
#include <dlfcn.h>
#include <cassert>
#include "obj.hpp"

// name mapping: public name to inner name
std::map<std::string, std::string> funcNameMap = {{"add", "func1"}, {"sub", "func2"}};

int retrieve_fn(void *dl_handler, std::string funcName, obj o) {
    assert(dl_handler != NULL && funcNameMap.count(funcName) != 0);
    auto real_fn_name = funcNameMap[funcName];
    auto fn = (ftype)dlsym(dl_handler, real_fn_name.c_str());
    auto dl_err = dlerror();
    if (dl_err) {
        std::cerr << "Load failed: " << dl_err << std::endl;
        return -999;
    }
    return fn(o);
}

int main(){
    obj o;
    o.num1 = 1;
    o.num2 = 2;
    // open dynamic shared library
    auto dl_name = "./functions.so";
    auto dl_handler = dlopen(dl_name, RTLD_LAZY);
    auto dl_err = dlerror();
    if (dl_err) {
        std::cerr << "Open failed: " << dl_err << std::endl;
        return -1;
    }
    auto x = retrieve_fn(dl_handler, "add", o);
    std::cout << x << std::endl;
    x = retrieve_fn(dl_handler, "sub", o);
    std::cout << x << std::endl;
    dlclose(dl_handler);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)
  1. 从 构建动态共享库functions.cpp
class obj {               
  public:                 
    int num1;             
    int num2;             
};                        
// type of target functions
typedef int (*ftype)(obj);
Run Code Online (Sandbox Code Playgroud)
  1. 从 构建一个可执行文件main.cpp
#include "obj.hpp"

extern "C"
int func1(obj o) {
    return o.num1 + o.num2;
}
extern "C"
int func2(obj o) {
    return o.num1 - o.num2;
}
Run Code Online (Sandbox Code Playgroud)
  1. 运行并检查结果。
#include <iostream>
#include <map>
#include <dlfcn.h>
#include <cassert>
#include "obj.hpp"

// name mapping: public name to inner name
std::map<std::string, std::string> funcNameMap = {{"add", "func1"}, {"sub", "func2"}};

int retrieve_fn(void *dl_handler, std::string funcName, obj o) {
    assert(dl_handler != NULL && funcNameMap.count(funcName) != 0);
    auto real_fn_name = funcNameMap[funcName];
    auto fn = (ftype)dlsym(dl_handler, real_fn_name.c_str());
    auto dl_err = dlerror();
    if (dl_err) {
        std::cerr << "Load failed: " << dl_err << std::endl;
        return -999;
    }
    return fn(o);
}

int main(){
    obj o;
    o.num1 = 1;
    o.num2 = 2;
    // open dynamic shared library
    auto dl_name = "./functions.so";
    auto dl_handler = dlopen(dl_name, RTLD_LAZY);
    auto dl_err = dlerror();
    if (dl_err) {
        std::cerr << "Open failed: " << dl_err << std::endl;
        return -1;
    }
    auto x = retrieve_fn(dl_handler, "add", o);
    std::cout << x << std::endl;
    x = retrieve_fn(dl_handler, "sub", o);
    std::cout << x << std::endl;
    dlclose(dl_handler);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)