如何通用检测std::unique_ptr及实现空指针变体判断?
一、通用检测std::unique_ptr(支持const&和自定义删除器)
要判断一个类型是否为std::unique_ptr(包含带自定义删除器、const引用等变体),可以通过类型 trait实现:
#include <memory> #include <type_traits> // 基础模板:匹配非unique_ptr类型 template<typename T> struct is_unique_ptr : std::false_type {}; // 偏特化:匹配任意T和Deleter的std::unique_ptr template<typename T, typename Deleter> struct is_unique_ptr<std::unique_ptr<T, Deleter>> : std::true_type {}; // 处理const、volatile、引用修饰的情况 template<typename T> struct is_unique_ptr<const T> : is_unique_ptr<T> {}; template<typename T> struct is_unique_ptr<volatile T> : is_unique_ptr<T> {}; template<typename T> struct is_unique_ptr<const volatile T> : is_unique_ptr<T> {}; template<typename T> struct is_unique_ptr<T&> : is_unique_ptr<T> {}; template<typename T> struct is_unique_ptr<T&&> : is_unique_ptr<T> {}; // 辅助变量模板,简化使用 template<typename T> constexpr bool is_unique_ptr_v = is_unique_ptr<T>::value;
测试示例
#include <iostream> int main() { std::unique_ptr<int> up; const std::unique_ptr<int, std::default_delete<int>>& cup_ref = up; std::cout << std::boolalpha; std::cout << is_unique_ptr_v<decltype(up)> << "\n"; // 输出true std::cout << is_unique_ptr_v<decltype(cup_ref)> << "\n"; // 输出true std::cout << is_unique_ptr_v<int*> << "\n"; // 输出false std::cout << is_unique_ptr_v<std::shared_ptr<int>> << "\n"; // 输出false return 0; }
二、一次性检测所有标准智能指针
如果需要判断类型是否为任意标准智能指针(std::unique_ptr/std::shared_ptr/std::weak_ptr),可以用std::disjunction组合多个trait:
// 检测std::shared_ptr的trait template<typename T> struct is_shared_ptr : std::false_type {}; template<typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {}; // 检测std::weak_ptr的trait template<typename T> struct is_weak_ptr : std::false_type {}; template<typename T> struct is_weak_ptr<std::weak_ptr<T>> : std::true_type {}; // 处理cv和引用修饰的特化(和is_unique_ptr逻辑一致,此处省略重复代码) template<typename T> struct is_shared_ptr<const T> : is_shared_ptr<T> {}; template<typename T> struct is_weak_ptr<const T> : is_weak_ptr<T> {}; // 统一的智能指针检测trait template<typename T> struct is_smart_ptr : std::disjunction< is_unique_ptr<T>, is_shared_ptr<T>, is_weak_ptr<T> > {}; // 辅助变量模板 template<typename T> constexpr bool is_smart_ptr_v = is_smart_ptr<T>::value;
三、实现IsEmptyVariantOfPointers的enable_if条件
要让函数仅在std::variant<T...>的所有参数都是可与nullptr比较的指针类型(裸指针、unique_ptr、shared_ptr)时实例化,需要两步:
步骤1:实现单个类型的空指针兼容检测
#include <utility> // 用于std::void_t // 基础模板:默认不兼容 template<typename T, typename = void> struct is_nullptr_compatible : std::false_type {}; // 匹配裸指针 template<typename T> struct is_nullptr_compatible<T*, void> : std::true_type {}; // 匹配能与nullptr比较的类型(如智能指针) template<typename T> struct is_nullptr_compatible<T, std::void_t<decltype(std::declval<T>() == nullptr)>> : std::true_type {}; // 辅助变量模板 template<typename T> constexpr bool is_nullptr_compatible_v = is_nullptr_compatible<T>::value;
步骤2:填充enable_if条件
用std::conjunction_v确保variant的所有参数都满足空指针兼容:
#include <variant> template<typename... T> std::enable_if_t<std::conjunction_v<is_nullptr_compatible<T>...>, bool> IsEmptyVariantOfPointers(const std::variant<T...>& variant) { bool emptyVariant = true; std::visit([&emptyVariant](auto&& arg) { emptyVariant = (arg == nullptr); }, variant); return emptyVariant; }
测试示例
int main() { std::variant<int*, std::unique_ptr<int>, std::shared_ptr<int>> var1; std::variant<int*, std::unique_ptr<int, std::default_delete<int>>> var2; std::variant<int, std::string> var3; // 非指针类型,函数不会实例化 var1 = nullptr; std::cout << IsEmptyVariantOfPointers(var1) << "\n"; // 输出true var2 = std::make_unique<int>(42); std::cout << IsEmptyVariantOfPointers(var2) << "\n"; // 输出false // IsEmptyVariantOfPointers(var3); // 编译错误,符合预期 return 0; }
补充说明
std::void_t用于SFINAE检测:如果arg == nullptr是合法表达式,则特化版本生效,判定为兼容。std::conjunction_v会检查所有模板参数是否都满足条件,只要有一个不满足,函数就不会被实例化。- 该方案无需重载模板函数,通过trait统一判断所有合法类型。
内容的提问来源于stack exchange,提问作者isrepeat
相关产品推荐
相关产品推荐

