c++ - CRTP 与模板专业化和标签调度
问题描述
我试图找出 CRTP 习语相对于模板专业化的优缺点。假设我想创建一个“渲染器”类,渲染器将使用“Vulkan”或“OpenGL”实现。
使用 CRTP:
template <typename T>
class Renderer
{
public:
void draw(Shape s) { static_cast<T*>(this)->drawImpl(s); };
};
class VulkanRenderer : public Renderer<VulkanRenderer>
{
public:
void drawImpl(Shape s) { /* Vulkan implementation */};
};
class OpenGLRenderer : public Renderer<OpenGLRenderer>
{
public:
void drawImpl(Shape s) { /* OpenGL implementation */ };
};
使用模板特化和类标签:
class Vulkan;
class OpenGL;
template<typename T>
class Renderer
{
public:
Renderer() { assert(false, "Type not support"); }
void draw(Shape s);
};
template<>
class Renderer<Vulkan>
{
public:
void draw(Shape s) { /* Vulkan implementation */ };
};
template<>
class Renderer<OpenGL>
{
public:
void draw(Shape s) { /* OpenGL implementation */ };
};
一种方法相对于另一种方法是否有某些优势?是否有某些事情我可以用一个做而我不能用另一个做?静态多态性技术有什么替代品吗?
此外,这些方法中的任何一种简单地定义单独的类(例如“VulkanRenderer”和“OpenGLRenderer”)是否有任何优势。此外,概念可能不是这两者的更好方式吗?
解决方案
使用 CRTP,您可以将任何共享代码/类型/常量等放入基本模板,同时支持这两种实现。如果您没有要分享的内容,那么使用 CRTP 毫无意义。它确实具有通常易于管理的缺点,即动态创建的派生对象有可能通过基类指针意外或粗心删除,从而导致未定义的行为。
使用类标签,与拥有两个不相关的类的唯一区别是,它更容易约束其他模板以需要某种类型的渲染器(即template <typename ARenderer> void f(Renderer<ARenderer>& r);
),而不是对不相关的类有要求std::is_same_v<T, OpenGLRenderer> || std::is_same_v<T, VulcanRenderer>
- 没有太多实用程序。如果渲染器除了接口的语义之外真的没有任何共同点,那么这是一个选择。
推荐阅读
- python - Python 数组 rows*1column numpy for numpy.dot(matrix,matrix2)
- javascript - React 组件无法读取未定义的属性
- python - 在 Raspbian 上手动安装 Python 库
- azure - Sql Server 中是否有办法查找视图中的哪些列未编入索引
- intellij-idea - 不要在 PhpStorm 中封装 else ifs
- mercurial - 查找更改 TortoiseHg 中特定文件的所有提交
- php - Laravel 5.6 - 更新唯一属性
- css - asp.net core Angular Template如何添加site.css
- javascript - 为什么在 process.env 上定义属性会导致奇怪的条件分支?
- ios - 使用单个推送动画推送和呈现视图控制器