admin管理员组

文章数量:1612391

奇特的递归模板模式(Curiously Recurring Template Pattern, CRTP)代表类实现技术中一种通用的模式,即派生类将本身作为模板参数传递给基类。 最简单的情形如下:

template<typename Derived>
class CuriousBase{

};

class Curious : public CuriousBase<Curious>{

};

在第一个示例中,CRTP有一个非依赖型基类:类Curious 不是模板,因此免于与依赖型基类的名字可见性等问题纠缠。不过,这并非CRTP的本质特性,请看:

template<typename  T>
class CurioutTemplate : public CuriousBase<CurioutTemplate<T>>{

};

从这个示例出发,不难再举出使用模板的模板参数的方式:

template<template<typename > class Derived>
class MoreCuriousBase{

};

template<typename  T>
class MoreCurious : public MoreCuriousBase<MoreCurious>{

};

CRTP的一个简单应用是记录某个类的对象构造的总个数。数对象个数很简单,只需要引入一个整数类型的静态数据成员,分别在构造函数和析构函数中进行递增和递减操作。不过,要在每个类里面都这么写就很累了。有了CRTP,我们可以先写一个模板:

template<typename CountedType>
class ObjectCounter{
private:
    static  size_t  count;

protected:
    ObjectCounter(){
        ++ObjectCounter<CountedType>::count;
    }
    
    ObjectCounter(ObjectCounter<CountedType> const  &){
        ++ObjectCounter<CountedType>::count;
    }
    
    ~ObjectCounter(){
        --ObjectCounter<CountedType>::count;
    }

public:
    static size_t  live(){
        return ObjectCounter<CountedType>::count;
    }
};

template<typename CountedType>
size_t  ObjectCounter<CountedType>::count = 0;

如果想要数某个类的对象存在的个数,只需要让该类从模板ObjectCounter派生即可。以一个字符串类为例:

template<typename CharT>
class MyString : public ObjectCounter<MyString<CharT>>{

};
int main(){
    MyString<wchar_t> ws;

    printf("number of MyString<char>: %zu\n", MyString<char>::live());
    printf("number of MyString<wchar_t>: %zu\n", MyString<wchar_t>::live());
    printf("number of MyString<wchar_t>: %zu\n", ws.live());
}


一般来说,CRTP适用于仅能用作成员函数的接口(比如构造函数、析构函数、operator[]等)的实现提取出来

本文标签: 递归奇特模板模式