如何为 std::unique_ptr 创建一个有效的 C++ 别名模板
How can I make a valid C++ alias template for std::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
的数组和标量版本的别名?
您似乎在尝试专门化 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
。
当然,这一切都毫无意义,但我认为您的真实 Deleter
与 std::default_delete
不同。
你应该向我们展示你的 ArrayDeleter
但是...你确定你不能用唯一的 using
和 std::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 说
I've edited the question to include an example ArrayDeleter implementation
不确定(我在模板数组特化方面犯了很多错误)但我想如果您可以按如下方式修改 ArrayDeleter
,那应该可以工作
template <typename>
struct ArrayDeleter;
template <typename T>
struct ArrayDeleter<T[]>
{ void operator()(T* ptr) { delete [] 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
的数组和标量版本的别名?
您似乎在尝试专门化 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
。
当然,这一切都毫无意义,但我认为您的真实 Deleter
与 std::default_delete
不同。
你应该向我们展示你的 ArrayDeleter
但是...你确定你不能用唯一的 using
和 std::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 说
I've edited the question to include an example ArrayDeleter implementation
不确定(我在模板数组特化方面犯了很多错误)但我想如果您可以按如下方式修改 ArrayDeleter
,那应该可以工作
template <typename>
struct ArrayDeleter;
template <typename T>
struct ArrayDeleter<T[]>
{ void operator()(T* ptr) { delete [] ptr; } };