c++ CRTP(Curiously Recurring Template Pattern)

本文介绍了在学习LLVMtutor时遇到的CRTP(CuriouslyRecurringTemplatePattern)模板编程技术,探讨了其工作原理、优点(如高性能多态和代码生成)以及潜在问题(如继承错误和方法覆盖),并提供了使用和避免CRTP陷阱的技巧。
摘要由CSDN通过智能技术生成

第一次遇到这个知识点是在学习 LLVM tutor 时遇到的

struct HelloWorld : PassInfoMixin<HelloWorld>

 收集了一些资料帮助理解并在此进行记录。

Basic

这种写法被称为 CRTP 奇异重复模板模式技术。

奇异和重复确实是我第一次看到这种代码的感受。因为HelloWorld的继承对象又模板引用了HelloWorld, 第一次读感到这个继承很怪。

定义

cppreference.com 对 CRPT 的定义如下:

The Curiously Recurring Template Pattern is an idiom in which a class X derives from a class template Y, taking a template parameter Z, where Y is instantiated with Z = X. 

最简结构如下:

template<class Z>
class Y {};
 
class X : public Y<X> {};

因为X继承的是 Y<X>, 在这种写法下, 只会有 X 是 Y<X> 的子类所以 在 Y 中通过 static_cast 可以安全转为 X, 而无需使用 dynamic_cast

我的理解

尽管使用了继承的语法,但是不应该从继承这种语义进行理解, 更加适合的理解是 X 和 Y 这两个类混合在了一起。

优点

添加公共方法

与普通的继承效果类似, 但是我们可以 static_cast 让代码更高效。即下面的高性能多态。

高性能多态

这个技术的优点在于相比常见的使用 virtual 实现的多态(需要在运行时查vtable), CRTP在编译时确定, 运行时效率自然相对高。

讨论 CRTP 的效率提高文章:The cost of dynamic (virtual calls) vs. static (CRTP) dispatch in C++ - Eli Bendersky's website

可以使用Derived类型的信息

可以减少一些接口的实现成本

在 llvm 的PassInfoMixin中, 我们可以看到它利用了 Derived 自动生成 pass 的 ClassName, 并根据 ClassName 查 PassName

可能出现的问题

继承错误

class Derived1 : public Base<Derived1>
{
    ...
};

class Derived2 : public Base<Derived1> // bug in this line of code
{
    ...
};

Derived2 会产生未定义行为

在 tips 第一小节给出了相应的编译时检查写法。

方法覆盖

子类的重名方法会直接覆盖父类的非虚方法, 要注意方法的命名

接口风格的使用

X 继承的是 Y<X> 而不是 Y, 这产生的效果不同于 接口+实现 。 Y<X> y = X() 并调用方法会产生未定义的行为。重点在于把这两个类视为混合。

Tips

避免继承错误

template <typename T>
class Base
{
public:
    // ...
private:
    Base(){};
    friend T;
};

减少 static_cast 的出现次数

使用函数封装 static_cast

template <typename T>
struct crtp
{
    T& underlying() { return static_cast<T&>(*this); }
    T const& underlying() const { return static_cast<T const&>(*this); }
};

参考

Curiously Recurring Template Pattern - cppreference.com

The Curiously Recurring Template Pattern (CRTP) - Fluent C++

What the Curiously Recurring Template Pattern can bring to your code - Fluent C++

An Implementation Helper For The Curiously Recurring Template Pattern - Fluent C++

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值