奇异递归Template有啥奇的?

如果一个模版看起来很头痛,那么大概率这种模版是用来炫技,没啥用的,但是CRTP这个模版,虽然看起来头大,但是却经常被端上桌~

奇异递归模板模式(Curiously Recurring Template Pattern, CRTP)是一种 C++ 模板编程技巧,用于实现静态多态。这种模式利用模板递归来允许一个类继承自一个模板类,其中模板参数是该类自身。这种模式可以用于各种用途,包括实现类型安全的单例模式、静态接口和性能优化。

CRTP基本概念

在 CRTP 模式中,一个类 Derived 继承自一个模板类 Base,这个模板类 Base 的模板参数是 Derived 自身。这样做的好处是允许在编译时确定 Derived 类型的信息,从而在不需要运行时多态的情况下实现多态行为。以下是 CRTP 的基本示例,展示了如何使用 CRTP 模式实现一个简单的静态接口:

cpp 复制代码
#include <iostream>
using namespace std;

template <typename Child>
struct Base
{
void interface()
{
    static_cast<Child*>(this)->implementation();
}
};

struct Derived : Base<Derived>
{
void implementation()
{
    cout << "Derived implementation\n";
}
};

int main()
{
    Derived d;
    d.interface();  // Prints "Derived implementation"

    return 0;
}

CRPT模板展开

遇到CRPT不要慌,一慌忘光光,为了认识这种代码的本质,我们不妨用Insights将其展开 , C++ Insights

cpp 复制代码
#include <iostream>
using namespace std;

template<typename Child>
struct Base
{
  inline void interface()
  {
    static_cast<Child *>(this)->implementation();
  }
  
};

/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Base<Derived>
{
  inline void interface()
  {
    static_cast<Derived *>(this)->implementation();
  }
  
  // inline constexpr Base() noexcept = default;
};

#endif

struct Derived : public Base<Derived>
{
  inline void implementation()
  {
    std::operator<<(std::cerr, "Derived implementation\n");
  }
  
  // inline constexpr Derived() noexcept = default;
};

int main()
{
  Derived d;
  static_cast<Base<Derived>&>(d).interface();
  return 0;
}

可以发现,展开的代码平平无奇,一目了然。

  • Base 类是一个模板类,它接受一个 Derived 类型作为模板参数。
  • Derived 类继承自 Base<Derived>,从而在 Base 中能够静态地调用 Derived 类中的方法。

另一个CRPT实例

以下是一个稍微复杂一点使用 CRTP 实现策略模式的例子:

cpp 复制代码
#include <iostream>

// CRTP 基类
template <typename Derived>
class Strategy {
public:
void execute() {
    // 调用 Derived 类中的实现
    static_cast<Derived*>(this)->perform();
}
};

// 具体策略 1
class ConcreteStrategy1 : public Strategy<ConcreteStrategy1> {
public:
void perform() {
    std::cout << "ConcreteStrategy1 implementation" << std::endl;
}
};

// 具体策略 2
class ConcreteStrategy2 : public Strategy<ConcreteStrategy2> {
public:
void perform() {
    std::cout << "ConcreteStrategy2 implementation" << std::endl;
}
};

int main() {
    ConcreteStrategy1 s1;
    ConcreteStrategy2 s2;

    s1.execute(); // 输出 "ConcreteStrategy1 implementation"
    s2.execute(); // 输出 "ConcreteStrategy2 implementation"

    return 0;
}

在这个示例中,Strategy 是 CRTP 基类,它定义了一个 execute 方法,该方法调用派生类的 perform 方法。具体策略类 ConcreteStrategy1ConcreteStrategy2 实现了不同的 perform 方法。这样,Strategy 基类就能够静态地调用不同的策略实现。

总结

看到CRPT,第一眼应该想到,这玩意没什么特别的,就是为了实现静态多态的。

  • 静态体现在哪儿,都是模版函数,在编译期都已经展开,函数调用是写死的
  • 多态体现在哪儿,调佣基类的公用接口,最后会执行子类的具体实现,这一点和虚函数多态有点相似,但这种多态是静态的。

所以,CRPT就这点东西。

相关推荐
唐诺4 小时前
几种广泛使用的 C++ 编译器
c++·编译器
冷眼看人间恩怨5 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客5 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin5 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos6 小时前
c++---------数据类型
java·jvm·c++
十年一梦实验室7 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0017 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
这是我587 小时前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
fpcc7 小时前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
呆萌很8 小时前
C++ 集合 list 使用
c++