在运行时选择同一函数的版本

Select a version of the same function in runtime

本文关键字:函数 版本 运行时 选择      更新时间:2023-10-16

我目前正在做一个项目,每次程序运行时都可以调用同一算法的 4 个版本之一(涉及不同的并行编程框架 + 其顺序类似物)。

所有这 4 个参数都是相同的,并行框架细节将在函数本身内部处理。

我是C++新手,所以真的不知道是否可以更改function()指向的代码并根据命令行参数选择正确的版本。

警告:前面有可怕的伪代码:

switch(version){
    case OMP:
        // make function() point to 1st version
    case CUDA:
        // ... to function2()
    case OCL:
        // ... to function3()
    case SEQ:
    default:
        // ... to function0()
}
// ...
while(condition){
    // call function()
}

所以我试图找出一种优雅的方式来做到这一点,同时将不同的算法放在单独的文件中,只在主例程中处理 I/O。某种行为模式?

如果你有普通的函数并且不需要类层次结构,你可以使用std::function

std::function<void (int, float)> target;
switch(version){
    case OMP: target = function1; break;
    case CUDA: target = std::bind(function2, "hello", _1, _2); break;
    case OCL: target = function3; break;
    case SEQ: target = function4; break;
    default: target = function0; break;
}
target(100, 3.14);

这是策略模式的典型示例。策略模式的基本思想是,您将拥有一个抽象的Strategy它将具有纯虚拟executerun方法。每个不同的算法或策略都会有具体的子类。

对于您的情况,大纲可以是这样的:

class BaseStrategy {
    virtual void execute(params...) = 0;
}
class OMPStrategy : public BaseStrategy {
    // implement execute method for OMP
}
class CUDAStrategy : public BaseStrategy {
    // implement execute method for CUDA
}
// etc

现在,在需要选择一个版本的方法中,您将根据您的输入实例化正确的策略对象并对其调用execute

像这样:

BaseStrategy *strategy;
switch(version){
    case OMP:
        strategy = new OMPStrategy();
        break;
    case CUDA:
        strategy = new CUDAStrategy();
        break;
    case OCL:
        strategy = new OCLStrategy();
        break;
    case SEQ:
        strategy = new SEQStrategy();
        break;
    default:
        strategy = new DefaultStrategy();
}
// now call it
while(condition){
    strategy->execute();
}
// delete strategy when done
delete strategy;

通过这种方式,您可以在不同的类中对不同的算法进行干净的单独实现。

注意:如注释中所述,如果引发异常,则可能会出现内存泄漏。如果您使用的是 c++11,那么使用 std::shared_ptrstd::unique_ptr 将比使用原始指针更好。

如果你使用的是 Linux(可能还有其他 Unix),你可以在运行时使用 dlopen() 加载正确的库函数,参见 'man 3 dlopen'。

dlopen 系列在您有一个主应用程序并希望能够使用例如较新版本的插件库进行热修补的情况下也很有用。原则上,甚至不必重新启动主应用程序即可升级插件。

自从我在Windows中入侵以来已经有一段时间了,但是Windows和Mac中也很有可能存在类似于dlopen的东西。(Mac是基于BSD变体的,所以即使是dlopen()也可以工作)。