如何用C++参数包与模板函数区分满足concept的匿名结构体?
问题
我定义了一个C++20的concept myrequirement:
template<typename T> concept myrequirement= requires(T s) { { s.type() } -> std::same_as<uint8_t>; }; enum MyType { TYPE1, TYPE2, TYPE3, };
使用者可以编写满足该约束的匿名结构体实例:
struct { static constexpr uint8_t type() { return TYPE1;} } foo; struct { static constexpr uint8_t type() { return TYPE2;} } bar; struct { static constexpr uint8_t type() { return TYPE3;} } baz;
我希望能通过类型值获取对应的实例,比如:
auto my_struct = get_instance<TYPE1>();
原本尝试用参数包实现,但编译失败:
template<uint8_t type, myrequirement... StructTypes> constexpr auto& get_instance_amongst(const StructTypes&... structs) { // 如何实现? } template<uint8_t type> constexpr auto& get_instance() { return get_instance_amongst(foo, bar, baz); }
请问有没有可行的实现方式?比如用折叠表达式?
可行实现方案
方法一:折叠表达式结合constexpr分支判断
利用C++20的constexpr条件判断和折叠表达式,逐个检查实例的type()是否匹配,找到后返回对应引用。同时添加静态断言处理无匹配项的情况:
#include <type_traits> #include <cstdint> // 保留原concept、枚举、实例定义... // 辅助函数:检查单个实例是否匹配目标类型 template<uint8_t TargetType, myrequirement T> constexpr const T* match_instance(const T& inst) { if constexpr (T::type() == TargetType) { return &inst; } else { return nullptr; } } template<uint8_t TargetType, myrequirement... Ts> constexpr auto& get_instance_amongst(const Ts&... insts) { const auto* matched = nullptr; // 折叠表达式遍历所有实例,收集匹配的指针 ( [&] { if (const auto* p = match_instance<TargetType>(insts); p != nullptr) { matched = p; } }(), ... ); // 静态断言确保找到唯一匹配项 static_assert(matched != nullptr, "No matching instance found for the given type"); return *matched; } template<uint8_t TargetType> constexpr auto& get_instance() { return get_instance_amongst<TargetType>(foo, bar, baz); } // 测试示例 int main() { constexpr auto& inst1 = get_instance<TYPE1>(); static_assert(inst1.type() == TYPE1); constexpr auto& inst2 = get_instance<TYPE2>(); static_assert(inst2.type() == TYPE2); }
方法二:std::tuple存储+编译期索引查找
将所有实例存入std::tuple,通过编译期索引遍历查找匹配项:
#include <type_traits> #include <cstdint> #include <tuple> // 保留原concept、枚举、实例定义... // 编译期查找tuple中匹配的索引 template<uint8_t TargetType, typename Tuple, std::size_t... Idxs> constexpr std::size_t find_match_idx(std::index_sequence<Idxs...>) { // 利用折叠表达式筛选匹配索引(假设唯一匹配) return ( (std::tuple_element_t<Idxs, Tuple>::type() == TargetType ? Idxs : 0) + ... ); } template<uint8_t TargetType> constexpr auto& get_instance() { constexpr auto instances = std::tie(foo, bar, baz); constexpr auto match_idx = find_match_idx<TargetType, decltype(instances)>( std::make_index_sequence<std::tuple_size_v<decltype(instances)>>{} ); static_assert(std::tuple_element_t<match_idx, decltype(instances)>::type() == TargetType, "No matching instance"); return std::get<match_idx>(instances); }
核心说明
- 匿名结构体特性:每个匿名结构体都是独立类型,参数包
StructTypes...会包含多个不同类型,折叠表达式可逐个处理。 - 编译期执行:所有匹配逻辑在编译阶段完成,无运行时开销。
- 唯一性保障:需确保每个TYPE值对应唯一实例,否则静态断言会触发编译错误。
内容的提问来源于stack exchange,提问作者grybouilli
相关产品推荐
相关产品推荐

