在类<std :: unique_ptr <b>&gt;中强制模板函数为T = B *

时间:2016-09-27 04:40:25

标签: c++ templates c++11 unique-ptr template-specialization

我有一个存储类,它可以添加/删除元素。

它的大多数公共函数都有一个非常相似的签名,如图所示: -

template<class T> class Storage{
    public: void add(T& t){ ... }
    //... other fields,functions
}

一件好事是T可以是值或原始指针。

现在我想升级此存储空间以支持T=std::unique_ptr 这就是我想要实现的目标: -

Storage<std::unique_ptr<B>> store;
B* b = new B();
store.add(b);   //my attempt - it is currently not supported

以下是支持新功能的草稿: -

template<class T> class Storage{
    public: template<class TWeak> void add(TWeak& tw){  ...   }
    //... other fields,functions
}

从草案中,我认为使用TWeak作为模板参数有点危险 - TWeak可以是任何东西。

与我的意图相反,TWeak只能T's weakpointer,粗略地说。

更具体地说,我想强制执行这条规则: -

When   T=std::unique_ptr<B>   ==>    TWeak have to be B* or std::unique_ptr<B>
When   T=B*                   ==>    TWeak have to be B*
When   T=B                    ==>    TWeak have to be B

如何优雅地执行规则?
具有2个add函数的解决方案仍然可以接受。

2 个答案:

答案 0 :(得分:1)

  

更具体地说,我想强制执行这条规则: -

     

T=std::unique_ptr<B> ==&gt; TWeak必须是B*或std :: unique_ptr

     

T=B* ==&gt; TWeak必须为B*

     

T=B ==&gt; TWeak必须为B

您可以编写一个带有专业化的“强制执行者”类,如下所示:

#include <type_traits>
#include <memory>

template<typename T, typename B, typename Tweak>
class tweak_enforcer
{   
    static_assert(std::is_same<Tweak, B>::value, "must be of same type");
};

template<typename B, typename Tweak>
class tweak_enforcer<std::unique_ptr<B>, B, Tweak>
{
    static_assert(std::is_same<Tweak, B*>::value || std::is_same<Tweak, std::unique_ptr<B>>::value, "must be of pointer type");
};

每个专精都使用static_assert通过std::is_same检查一个或多个预期类型匹配。

然后您可以像这样使用它(取消注释任何注释行会导致构建失败并显示相应的消息):

int main() {
    { tweak_enforcer<int, int, int> dummy; }
    // { tweak_enforcer<int *, int *, int> dummy; }
    { tweak_enforcer<int *, int *, int *> dummy; }
    { tweak_enforcer<std::unique_ptr<int>, int, int *> dummy; }
    { tweak_enforcer<std::unique_ptr<int>, int, std::unique_ptr<int>> dummy; }
    // { tweak_enforcer<std::unique_ptr<int>, int, std::shared_ptr<int>> dummy; }
}   

答案 1 :(得分:1)

为了简化界面,您可以使用专门化扩展Storage,该专门化为unique_ptr等封闭类型提供:

template<class T>
class Storage<std::unique_ptr<T>> : public Storage<T*>{
  public: using Storage<T*>::add;
  public: void add(std::unique_ptr<T>& t){ ... }  // 
};

我们继承Storage<T*>因为:

    根据您的要求,
  1. T*unique_ptr<T>相得益彰 问题
  2. 它包括所有常用方法。像add()这样的特殊方法 是单独定义的,using指令用于取消隐藏 基本方法
  3. 用法:

    Storage<int> si; si.add(/*int variable*/);
    Storage<int*> spi; spi.add(/*int* variable*/);
    Storage<std::unique_ptr<int>> su; su.add(/*int* or unique_ptr<int> variable*/);
    

    这是demo