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

时间:2017-08-09 01:35:40

标签: c++ header-files preprocessor-directive

目前我正在编写一个类,它支持使用预处理器定义在cpugpu上进行数据处理,以确定要包含哪个header文件。

IE

#ifdef CPU_work
#include "cpu_backend.h"
#endif

#ifdef GPU_work
#include "gpu_backend.h"
#endif

class Work {
//Implementation dependant upon included header 
}

然而,在某些情况下我可能需要两种变体。无论如何,我可以做类似......

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。

2 个答案:

答案 0 :(得分:2)

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

Work

您现在无法使用基类foo,因为它是抽象的,您不会无意中调用派生类barFZAccordionTableView,因为它们是私有成员基类。

答案 1 :(得分:0)

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

首先使用模板特化,模板默认参数和(当然)一些宏。

检查出来:

Option Explicit

Sub Clear_Table(ct As Range)

    ct.ClearContents

End Sub

Sub rite()

    Clear_Table Range("E10")
    Range("E10").Value = "dwsds"

End Sub
// 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"; }
};

如果您使用MSVC,则可以简化上述示例,从而消除// 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; } #define

  

技巧: MSVC(2017年和更早版本)允许省略那些宏阈值,只是忽略第二个声明,如果它们相遇   相同的编译单元,如下:

#ifndef
     

这不符合标准。 Standard不允许两次指定默认模板args。

同时,这个解决方案有一些缺点:

  • 当您同时包含两个标题时,有人仍然可以说template<class Method = UseCPU> struct Backend; template<class Method = UseGPU> struct Backend; 使用 指定的第一个 标头指定的后端。 但是,如果编译器强迫某人指定一个,那会更好 在这种情况下显式后端类型,因为否则它 依赖于标题包含顺序,这是坏的(问好 宏)。

  • 此外,它假设两个后端都具有相同的API(如Work<> 在我的情况下)

可能的修复:

  • 我确信在两者都可以使编译器出错 包含标头,但没有指定明确的后端,但它 可能涉及更多的预处理器或一些SFINAE ......

  • 如果您的后端有不同的API,那么您可以插入一些 Info()需要或(最好)使用C ++ 17 #ifdef如果您有权限 这样很酷的功能:)