如何用模板为不同结构体/容器编写void函数?无成员B的结构体如何处理?
适配不同容器的模板函数实现及成员缺失处理
一、基础模板化改造
把原函数改为模板函数,通过模板参数Container适配任意类型的结构体或容器,只要该类型具有membA、membB成员且能被dosomething_with处理:
template <typename Container> void func(Container& C) { C.membA = 1; C.membB = 2; dosomething_with(C); }
这个版本的局限性在于:如果传入的类型没有membB成员,编译会直接报错。要解决这个问题,需要根据类型是否包含membB来分支处理。
二、处理成员不存在的情况
方法1:C++20 用概念(Concepts)实现分支
C++20的概念特性可以直接检测类型是否包含指定成员,从而编写不同的重载版本:
首先定义一个检测membB是否存在的概念:
template <typename T> concept HasMembB = requires(T t) { t.membB; };
然后编写两个重载:
// 当类型包含membB时调用 template <HasMembB Container> void func(Container& C) { C.membA = 1; C.membB = 2; dosomething_with(C); } // 当类型不包含membB时调用 template <typename Container> void func(Container& C) requires (!HasMembB<Container>) { C.membA = 1; dosomething_with(C); }
方法2:C11/C17 用SFINAE技术实现分支
在C++20之前,可以借助SFINAE(替换失败不是错误)技术,通过类型特性检测成员是否存在:
第一步:定义检测membB的类型特性
#include <type_traits> template <typename T> struct has_membB { private: // 如果T有membB,匹配这个重载,返回std::true_type template <typename U> static std::true_type test(decltype(&U::membB)); // 否则匹配这个重载,返回std::false_type template <typename U> static std::false_type test(...); public: static constexpr bool value = decltype(test<T>(nullptr))::value; }; // C++14及以后可用的简化别名 template <typename T> constexpr bool has_membB_v = has_membB<T>::value;
第二步:用std::enable_if实现重载
// 包含membB的版本 template <typename Container> typename std::enable_if<has_membB_v<Container>, void>::type func(Container& C) { C.membA = 1; C.membB = 2; dosomething_with(C); } // 不包含membB的版本 template <typename Container> typename std::enable_if<!has_membB_v<Container>, void>::type func(Container& C) { C.membA = 1; dosomething_with(C); }
三、配套模板函数(可选)
如果dosomething_with也需要适配不同类型,同样需要将其改为模板函数:
template <typename Container> void dosomething_with(const Container& C) { // 根据容器类型执行对应逻辑 }
测试示例
// 包含membA和membB的结构体 struct StructWithAB { int membA; int membB; }; // 仅包含membA的结构体 struct StructOnlyA { int membA; }; int main() { StructWithAB s1; func(s1); // 调用赋值membB的版本 StructOnlyA s2; func(s2); // 调用跳过membB赋值的版本 return 0; }
内容的提问来源于stack exchange,提问作者Namal
相关产品推荐
相关产品推荐

