C++20如何通过std::type_identity标记从std::tuple中按类型取值
实现方案
该需求完全可以通过C++20特性实现,核心思路是编译期匹配tuple中继承了对应std::type_identity标记的元素类型,直接返回对应元素的引用即可。
实现代码
你只需要替换GetThing函数的实现即可,完整可运行代码如下:
#include <type_traits> #include <tuple> #include <utility> template<typename...Types> class Things { public: template<typename T> auto& GetThing() { return std::apply([](auto&... args) -> auto& { // 编译期统计匹配的类型数量 constexpr std::size_t match_count = (... + (std::is_base_of_v<std::type_identity<T>, std::remove_cvref_t<decltype(args)>> ? 1 : 0)); static_assert(match_count == 1, "匹配失败:不存在目标标记类型,或存在多个同标记的类型导致歧义"); // 找到匹配的元素返回引用 auto* matched = (... + [&](){ using U = std::remove_cvref_t<decltype(args)>; if constexpr (std::is_base_of_v<std::type_identity<T>, U>) { return &args; } else { return static_cast<U*>(nullptr); } }()); return *matched; }, things); } private: std::tuple<Types...> things{}; }; struct FooType {}; struct FooA : std::type_identity<FooType> {}; struct FooB : std::type_identity<FooType> {}; struct Bar {}; int main() { { Things<FooA, Bar> things1; auto& foo = things1.GetThing<FooType>(); static_assert(std::is_same_v<decltype(foo), FooA&>); } { Things<FooB, Bar> things2; auto& foo = things2.GetThing<FooType>(); static_assert(std::is_same_v<decltype(foo), FooB&>); } }
实现说明
- 利用C++20的泛型lambda和折叠表达式,编译期完成所有类型检查和匹配,没有运行时开销
- 内置静态断言检查匹配结果,当不存在匹配类型或者存在多个同标记的类型时,会直接抛出编译错误提示,避免运行时问题
- 完全兼容你给出的测试用例,两个static_assert都能正常通过
内容的提问来源于stack exchange,提问作者Lloyd
相关产品推荐
相关产品推荐

