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;