基于类模板参数的条件std::variant类型定义问题
动态构建std::variant成员类型的简洁可扩展方案
针对你的需求——在类模板Executor中根据模板参数动态生成std::variant类型的RequestType,同时避免占位类型和堆叠条件判断,这里提供一种基于类型列表拼接的方案,扩展性强且结构清晰。
核心思路
通过以下三步实现:
- 用工具类根据布尔参数选择生成包含目标类型的单元素tuple或空tuple
- 将多个这类tuple拼接成一个完整的类型tuple
- 将拼接后的tuple转换为
std::variant类型
这种方式无需嵌套条件判断,后续新增类似开关参数时,仅需添加一行类型选择代码即可。
实现代码
1. 条件类型选择工具
#include <variant> #include <tuple> // 前置声明业务类型 struct ReadRequest {}; struct InsertRequest {}; struct DeleteRequest {}; // 根据条件决定是否包含某个类型,返回对应tuple template<bool Include, typename T> struct ConditionalType { using type = std::tuple<T>; }; template<typename T> struct ConditionalType<false, T> { using type = std::tuple<>; }; template<bool Include, typename T> using ConditionalType_t = typename ConditionalType<Include, T>::type;
2. Tuple拼接工具
// 递归拼接多个tuple为一个 template<typename... Tuples> struct TupleCat; template<typename... Ts> struct TupleCat<std::tuple<Ts...>> { using type = std::tuple<Ts...>; }; template<typename... Ts, typename... Us, typename... Rest> struct TupleCat<std::tuple<Ts...>, std::tuple<Us...>, Rest...> { using type = typename TupleCat<std::tuple<Ts..., Us...>, Rest...>::type; }; template<typename... Tuples> using TupleCat_t = typename TupleCat<Tuples...>::type;
3. Tuple转Variant工具
// 将tuple类型转换为std::variant类型 template<typename Tuple> struct TupleToVariant; template<typename... Ts> struct TupleToVariant<std::tuple<Ts...>> { using type = std::variant<Ts...>; }; template<typename Tuple> using TupleToVariant_t = typename TupleToVariant<Tuple>::type;
4. 在Executor中定义RequestType
template<bool InsertsAllowed, bool DeletesAllowed> class Executor { public: using RequestType = TupleToVariant_t< TupleCat_t< std::tuple<ReadRequest>, // 始终包含的类型 ConditionalType_t<InsertsAllowed, InsertRequest>, ConditionalType_t<DeletesAllowed, DeleteRequest> // 后续新增开关参数时,直接添加该行即可: // ConditionalType_t<UpdatesAllowed, UpdateRequest> > >; };
验证示例
// 验证不同模板参数下的RequestType是否符合预期 using ReadOnlyExecutor = Executor<false, false>; static_assert(std::is_same_v<ReadOnlyExecutor::RequestType, std::variant<ReadRequest>>); using ReadInsertExecutor = Executor<true, false>; static_assert(std::is_same_v<ReadInsertExecutor::RequestType, std::variant<ReadRequest, InsertRequest>>); using FullExecutor = Executor<true, true>; static_assert(std::is_same_v<FullExecutor::RequestType, std::variant<ReadRequest, InsertRequest, DeleteRequest>>);
方案优势
- 无占位类型:生成的
std::variant仅包含需要的类型,完全可以安全创建引用 - 高扩展性:新增类似
UpdatesAllowed这类开关参数时,只需在TupleCat_t的参数列表中添加一行对应代码 - 结构清晰:避免了多层
std::conditional嵌套,逻辑一目了然
内容的提问来源于stack exchange,提问作者paulinho
相关产品推荐
相关产品推荐

