使用可变参数 CRTP

问题描述

我即将设计和实现一种智能指针工具包 - 一组类来定义各种类型的智能指针,如 unique_ptr、intrusive_ptr、shared_ptr、observation_ptr、tagged_ptr 等。顺便提一下,我在独立环境中工作我没有可用的 C++ 库。我的干预是避免代码重复,使其遵循优雅的设计原则。让我在那里描述我的想法。

设计注意事项: 我想使用可变参数 CRTP 方法来混合所需的指针特征和特征。对于每个功能集,都应该有一个特征类,如:

/* Functions to support move semantics like move constructor,move assignment operator */
template<typename DERIVED>
class MoveablePointer { ... };

/* Functions to manage pointee lifetime - using the deleter class */
/* EDIT: template<typename DERIVED,typename DELETER = DefaultDeleter<typename DERIVED::element_type>> */
template<typename DERIVED,typename DELETER> /* <-------- Default removed here as EDIT */
class Owning { 
public:
    using deleter_type = DELETER;
    
    /* ... */
};

/* Functions to use least significant bits effectively unused due to alignment to hold additional payload information */
template<typename DERIVED,typename TAGS,size_t ALIGNMENT>
class Tagged { ... };

然后使用可变参数CRTP模式将特征混合到一个智能指针类中:

template<template<typename> class... TRAITS>
struct make_traits {
    template<typename DERIVED>
    struct Traits : public TRAITS<DERIVED>... {};
};
template<typename T,template<typename> class POINTER_TRAITS>
class SmartPointer : public POINTER_TRAITS<SmartPointer<T,POINTER_TRAITS>> {
public:
    using pointer = T*;
    using element_type = T;

    /* ... */
};

template<typename T,typename DELETER = DefaultDeleter<T>>
using unique_ptr = SmartPointer<T,make_traits<MoveablePointer,Owning>>;

template<typename T>
using observer_ptr = SmartPointer<T,make_traits<Observing,NoNowning,copyable,Moveable>>;

/* ... and to continue defining type aliases to cover varIoUs smart pointer variations... */

基本上,一旦特定特征具有相同的模板参数集(仅 template<typename DERIVED>),这个想法似乎就可以工作。但如上例所示,情况并非如此,例如 Tagged trait 或 Owning trait 分别需要更多模板参数,如 ALIGNMENTDELETER

所以我的问题是 - 如何更改 make_traits 和 SmartPointer 类模板的实现以支持可变参数 trait 的模板参数?

非常感谢任何愿意帮助我的人!马丁

编辑:随着讨论在答案下方流动而调整代码...

解决方法

您可以使用可变参数模板:

template<template<typename,typename...> class... TRAITS>
//                        ^^^^^^^^^^^^^
struct make_traits {
    template<typename DERIVED>
    struct Traits : public TRAITS<DERIVED>... {};
};
template<typename T,template<typename> class POINTER_TRAITS>
class SmartPointer : public POINTER_TRAITS<SmartPointer<T,POINTER_TRAITS>> {
public:
    using pointer = T*;
    using element_type = T;

    /* ... */
};

template<typename T,typename DELETER = DefaultDeleter<T>>
using unique_ptr = SmartPointer<T,make_traits<MoveablePointer,Owning>::template Traits>;

template<typename T>
using observer_ptr = SmartPointer<T,make_traits<Observing,NonOwning,Copyable,MoveablePointer>::template Traits>;

Demo