如何让std::vector的serialize模板仅匹配可序列化的T类型?
问题描述
现有以下序列化模板函数:
template<typename T, std::enable_if_t<std::is_pod_v<T>, bool> = true > void serialize(const T & t) { /*serialize POD*/ } template<> void serialize(const std::string & t) { /*serialize string*/ } //....
需要添加一个std::vector的模板版本,要求仅当容器内的元素类型T本身可以被serialize()处理时,该模板才会被匹配。
解决方案
方法一:使用SFINAE与类型 trait(兼容C++11及以上)
首先定义一个类型 trait,用于检测给定类型T是否可以被serialize()函数处理:
// 自定义void_t,兼容C++11(C++17及以上可直接用std::void_t) template<typename...> using void_t = void; // 基础模板,默认标记为不可序列化 template<typename T, typename = void> struct is_serializable : std::false_type {}; // 特化版本:当对const T&调用serialize合法时,标记为可序列化 template<typename T> struct is_serializable<T, void_t<decltype(serialize(std::declval<const T&>()))>> : std::true_type {}; // 辅助变量模板,简化使用 template<typename T> constexpr bool is_serializable_v = is_serializable<T>::value;
然后利用这个trait来限制std::vector的序列化模板:
template<typename T, std::enable_if_t<is_serializable_v<T>, bool> = true> void serialize(const std::vector<T> & t) { // 实现vector的序列化逻辑,例如遍历每个元素调用serialize for (const auto& elem : t) { serialize(elem); } }
核心逻辑是通过SFINAE机制,只有当serialize(std::declval<const T&>())是合法表达式时,is_serializable_v<T>才会为true,此时std::vector的模板才会被编译器启用。
方法二:使用C++20 Concept(更简洁)
如果项目支持C++20,可以直接用Concept实现,代码更直观:
// 定义Serializable概念,要求能对const T&调用serialize template<typename T> concept Serializable = requires(const T& t) { serialize(t); }; // 仅当T满足Serializable概念时,匹配该模板 template<Serializable T> void serialize(const std::vector<T>& t) { // 序列化逻辑 for (const auto& elem : t) { serialize(elem); } }
Concept会自动检测T是否符合serialize()的调用要求,不符合的话该模板会被编译器直接忽略。
内容的提问来源于stack exchange,提问作者galinette
相关产品推荐
相关产品推荐

