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

C++ 在运行时选择同一函数的版本,c++,switch-statement,C++,Switch Statement,我目前正在从事一个项目,在这个项目中,每次程序运行时都可以调用同一算法的4个版本之一(涉及不同的并行编程框架+其顺序类似物) 所有这4个函数的参数都是相同的,并行框架细节将在函数本身内部处理 我对C++是全新的,所以实际上不知道是否有可能改变代码< 函数()/> >指向< /强>,并根据命令行参数选择正确的版本。< /P> 警告:前方是可怕的伪代码: switch(version){ case OMP: // make function() point to 1st ve

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

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

<>我对C++是全新的,所以实际上<强>不知道是否有可能改变代码< <代码>函数()/> >指向< /强>,并根据命令行参数选择正确的版本。< /P> 警告:前方是可怕的伪代码:

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);
std::功能目标;
交换机(版本){
案例OMP:目标=功能1;中断;
案例CUDA:target=std::bind(function2,“hello”、\u1、\u2);break;
案例OCL:目标=功能3;中断;
案例顺序:目标=功能4;中断;
默认值:target=function0;break;
}
目标(100,3.14);

如果您有普通函数,并且不需要类层次结构,那么可以使用
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);
std::功能目标;
交换机(版本){
案例OMP:目标=功能1;中断;
案例CUDA:target=std::bind(function2,“hello”、\u1、\u2);break;
案例OCL:目标=功能3;中断;
案例顺序:目标=功能4;中断;
默认值:target=function0;break;
}
目标(100,3.14);

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

对于您的情况,大纲可以如下所示:

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
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;
现在,在需要选择一个版本的方法中,您将根据输入实例化适当的策略对象,并对其调用
execute

大概是这样的:

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
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\u ptr
std::unique\u ptr
将比使用原始指针更好。

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

对于您的情况,大纲可以如下所示:

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
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;
现在,在需要选择一个版本的方法中,您将根据输入实例化适当的策略对象,并对其调用
execute

大概是这样的:

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
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_ptr
std::unique_ptr
将比使用原始指针更好。

如果您使用的是Linux(可能还有其他Unix),则可以在运行时使用dlopen()加载正确的库函数,请参阅“man 3 dlopen”

如果您有一个主应用程序,并且希望能够使用较新版本的插件库进行热补丁,则dlopen系列也很有用。原则上,升级插件甚至不需要重新启动主应用程序

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

如果您在Linux(可能还有其他Unix)上,您可以在运行时使用dlopen()加载正确的库函数,请参阅“man 3 dlopen”

如果您有一个主应用程序,并且希望能够使用较新版本的插件库进行热补丁,则dlopen系列也很有用。原则上,升级插件甚至不需要重新启动主应用程序


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

面向对象的方法是使用纯虚拟方法创建一个接口类,然后为每个for案例创建一个子类,并让每个子类实现该方法。在启动时动态分配相应子类的对象,并根据需要调用该对象上的虚拟方法。C风格的方法与之类似,只是您需要设置一个函数指针,而不是指向对象的指针。OOP方法是使用纯虚拟方法创建一个接口类,然后为每个for案例创建一个子类,并让每个子类实现该方法。在启动时动态分配相应子类的对象,并根据需要调用该对象上的虚拟方法。C风格的方法与之类似,只是您设置了一个函数指针,而不是指向对象的指针。Ick
std::bind
:很少值得这么做,bind是一种奇怪的方法。只需使用lambda即可。@Yakk:这是主观的。欢迎您将其作为竞争性答案发布。我已经用我的函数签名(
std::function target
)尝试了您的解决方案,但它给了我一些编译问题D:。Idk,如果它们涉及使用XCode的clang,或者只是因为我不能将那么长的模板用于这些类型