Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 编译同一类的两个不同实现_C++_Header Files_Preprocessor Directive - Fatal编程技术网

C++ 编译同一类的两个不同实现

C++ 编译同一类的两个不同实现,c++,header-files,preprocessor-directive,C++,Header Files,Preprocessor Directive,目前,我正在编写一个类,它支持在cpu或gpu上使用预处理器定义来确定要包含的头文件 即 然而,在某些情况下,我可能需要两种变体。我能做点什么吗,比如 namespace CPU { #define CPU_work //Generate implementation of WorkClass with cpu_backend.h } namespace GPU { #define GPU_work //Generate implementation of

目前,我正在编写一个类,它支持在
cpu
gpu
上使用预处理器定义来确定要包含的
头文件

然而,在某些情况下,我可能需要两种变体。我能做点什么吗,比如

namespace CPU {
    #define CPU_work
    //Generate implementation of WorkClass with cpu_backend.h
}
namespace GPU {
      #define GPU_work
      //Generate implementation of WorkClass with gpu_backend.h
}
因此,通过以下方式确定我想要的实现:

CPU::Work cpuObject;
GPU::Work gpuObject;
我也会很乐意做任何工作。
非常感谢JJ。

这可能是使用模板方法设计的地方。基类实现CPU和GPU共同的所有功能,然后在存在差异的地方使用抽象函数

class Work {
public:
    void execute() {
        // Do some initializing
        foo();
        // Do some middle stuff
        bar();
        // Do some final stuff
    }

private:
    virtual void foo() = 0;
    virtual void bar() = 0;
}

class CpuWork: public Work {
    virtual void foo() {
        // Do some CPU stuff
    }
    virtual void bar() {
        // Do some more CPU stuff
    }
}

class GpuWork: public Work {
    virtual void foo() {
        // Do some GPU stuff
    }
    virtual void bar() {
        // Do some more GPU stuff
    }
}
您现在不能意外地使用基类
Work
,因为它是抽象的,也不能意外地调用派生类
foo
bar
,因为它们是基类的私有成员。

有趣的问题:)如果我正确理解您的目标,我可以建议一些解决方案

首先使用模板专门化、模板默认参数和(当然)一些宏

看看这个:

// cpu_backend.h 
#define CPU_BACKEND

class UseCPU;

#ifndef GPU_BACKEND
template<class Method = UseCPU>
struct Backend;
#endif

template<>
struct Backend<UseCPU>
{
    char* Info() { return "CPU"; }
};
但这不是标准。标准不允许两次指定默认模板参数

同时,此解决方案几乎没有缺点:

  • 当您同时包含这两个标题时,有人仍然可以说
    Work
    ,这将 使用包含的第一个头指定的后端。 不过,如果编译器强制某人指定 在这种情况下,后端类型是显式的,否则 依赖于标题包含顺序,该顺序不正确(向 宏)

  • 此外,它假定两个后端都有相同的API(如
    Info()
    就我而言)

可能的修复方法包括:

  • 我确信当两者都发生时,编译器可能会给出错误 包含标头,但未指定显式后端,但 可能涉及更多的预处理器的事情或一些SFINAE

  • 如果后端确实有不同的API,那么可以插入一些API
    #ifdef
    在需要的地方或(最好)使用C++17
    如果constexpr(std::is_same()::value)
    如果您有访问权限 对于如此酷的功能:)


**我想我会有很多人对遗产发表评论。然而,除了对gpu/cpu的单行方法调用之外,这两个不同的版本将有相同的代码,尽管仅仅创建两个独立的子类就足够了,但我不想花时间复制/粘贴30多页的代码。这实际上是一个单接口“backend.h”的好例子其中,所有声明的函数都与单个名称空间和两个cpp文件相同,“cpu_work.cpp”和“gpu_work.cpp”以各自的特殊方式实现公共接口。在编译时正确的实现文件中的链接。C++中正确的方法是继承。打开C++书中的章节,说明如何创建继承父类的子类,并开始阅读。您将有一个基类和两个子类来实现适当的CPU或GPU特定功能。c++11标准库对时钟不是做了类似的事情吗
std::chrono::system_clock::now()
std::chrono::high_resolution_clock::now()
绝对是一个很酷的技巧,但我更愿意保持它的标准。看起来这只是在问虫子。对不起,可能是我弄错了。我提供的代码是标准的(我想是C++11)。VisualStudio中的“技巧”不是标准的,但它只允许您在没有
#ifndef GPU后端
和朋友的情况下做同样的事情。如果这就是您所说的“标准”:
// cpu_backend.h 
#define CPU_BACKEND

class UseCPU;

#ifndef GPU_BACKEND
template<class Method = UseCPU>
struct Backend;
#endif

template<>
struct Backend<UseCPU>
{
    char* Info() { return "CPU"; }
};
// gpu_backend.h
#define GPU_BACKEND

class UseGPU;

#ifndef CPU_BACKEND 
template<class Method = UseGPU>
struct Backend;
#endif 

template<>
struct Backend<UseGPU>
{
    char* Info() { return "GPU"; }
};
// main.cpp
// Try to swap comments on headers 
// and see how output changes

#include "cpu_backend.h"
//#include "gpu_backend.h"

#include <iostream>

template<class ... Method>
struct Work
{
    Work()
    {
        std::cout << "I use " << backend.Info() << std::endl;
    }

private:
    Backend<Method ...> backend;
};

int main()
{
    Work<> work;
    // Uncomment these two while including both headers
    //Work<UseCPU> cpuWork; 
    //Work<UseGPU> gpuWork;
    return 0;
}
template<class Method = UseCPU>
struct Backend;
template<class Method = UseGPU>
struct Backend;