如何为std :: unique_ptr创建有效的C ++别名模板

时间:2017-03-02 21:11:30

标签: c++ arrays c++11 templates unique-ptr

我想为std::unique_ptr创建一个提供我自己的删除功能的别名模板。

unique_ptr同时具有标量和数组实现,它们的定义如下:

template <class T, class D = default_delete<T>>
class unique_ptr // scalar

template <class T, class D>
class unique_ptr<T[], D> // array

我在尝试覆盖unique_ptr的标量和数组版本时遇到了麻烦。只为一个版本制作别名很容易,例如:

template<class T>
struct Deleter {
    void operator()(T* ptr) { delete ptr; }
};

template<class T>
using my_unique_ptr = std::unique_ptr<T Deleter<T>>;

但是当我尝试添加第二个别名时,就像这样:

template<class T>
struct ArrayDeleter {
    void operator()(T* ptr) { delete [] ptr; }
};
template<class T>
using my_unique_ptr = std::unique_ptr<T[], ArrayDeleter<T>>;

...我最终遇到编译器错误,因为“my_unique_ptr”不明确。

我的问题是:如何创建一个适用于unique_ptr的数组和标量版本的单一别名?

2 个答案:

答案 0 :(得分:4)

您似乎正在尝试专门化using声明。你可能没有。

template<class T>
struct my_unique_ptr_helper {
  using type = std::unique_ptr<T, Deleter<T>>;
};
template<class T>
struct my_unique_ptr_helper<T[]> {
  using type = std::unique_ptr<T[], ArrayDeleter<T>>;
};

template<class T>
using my_unique_ptr = typename my_unique_ptr_helper<T>::type;

现在这有缺点,因为它会完全阻止演绎。

我们可以通过将专业化转移到其他地方来解决这个问题。

template<class T>
struct Deleter {
  void operator()(T* ptr) const {
    delete ptr;
  }
};
template<class T>
struct ArrayDeleter {
  void operator()(T* ptr) const {
    delete[] ptr;
  }
};
template<class T>
struct Deleter<T[]>:ArrayDeleter<T> {}; // inheritance

现在:

template<class T>
using my_unique_ptr = std::unique_ptr<T, Deleter<T>>;

更简单,可以允许更多地扣除T

当然,这一切都毫无意义,但我认为你的真实Deleterstd::default_delete不同。

答案 1 :(得分:2)

您应该向我们展示您的ArrayDeleter,但是......您确定使用独特的usingstd::conditional无法解决问题吗?

我的意思是,像

template <typename T>
using my_unique_ptr = std::unique_ptr<T,
         typename std::conditional<std::is_array<T>::value,
                                   ArrayDeleter<T>,
                                   Deleter<T>>::type>;

---编辑---

OP说

  

我编辑了这个问题,以包含一个示例ArrayDeleter实现

不确定(我在模板数组专业化方面做了很多错误)但我认为如果您可以修改ArrayDeleter,则应该有效

template <typename>
struct ArrayDeleter;

template <typename T>
struct ArrayDeleter<T[]>
 { void operator()(T* ptr) { delete [] ptr; } };